/* $Id: ClpFactorization.cpp 2385 2019-01-06 19:43:06Z unxusr $ */
// Copyright (C) 2002, International Business Machines
// Corporation and others.  All Rights Reserved.
// This code is licensed under the terms of the Eclipse Public License (EPL).

#include "CoinPragma.hpp"
#if ABOCA_LITE
// 1 is not owner of abcState_
#define ABCSTATE_LITE 1
#endif
#include "ClpFactorization.hpp"
#ifndef SLIM_CLP
#include "ClpQuadraticObjective.hpp"
#endif
#include "CoinHelperFunctions.hpp"
#include "CoinIndexedVector.hpp"
#include "ClpSimplex.hpp"
#include "ClpSimplexDual.hpp"
#include "ClpMatrixBase.hpp"
#ifndef SLIM_CLP
#include "ClpNetworkBasis.hpp"
#include "ClpNetworkMatrix.hpp"
//#define CHECK_NETWORK
#ifdef CHECK_NETWORK
const static bool doCheck = true;
#else
const static bool doCheck = false;
#endif
#endif
#ifndef CLP_FACTORIZATION_NEW_TIMING
#define CLP_FACTORIZATION_NEW_TIMING
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
#include "CoinTime.hpp"
double factorization_instrument(int type)
{
  static int times[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
  static double startTime = 0.0;
  static double totalTimes[10] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 };
  if (type < 0) {
    assert(!startTime);
    startTime = CoinCpuTime();
    return 0.0;
  } else if (type > 0) {
    times[type]++;
    double difference = CoinCpuTime() - startTime;
    totalTimes[type] += difference;
    startTime = 0.0;
    return difference;
  } else {
    // report
    const char *types[10] = {
      "", "fac=rhs_etc", "factorize", "replace", "update_FT",
      "update", "update_transpose", "gosparse", "getWeights!", "update2_FT"
    };
    double total = 0.0;
    for (int i = 1; i < 10; i++) {
      if (times[i]) {
        printf("%s was called %d times taking %g seconds\n",
          types[i], times[i], totalTimes[i]);
        total += totalTimes[i];
        times[i] = 0;
        totalTimes[i] = 0.0;
      }
    }
    return total;
  }
}
#endif
//#############################################################################
// Constructors / Destructor / Assignment
//#############################################################################
#ifndef CLP_MULTIPLE_FACTORIZATIONS

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpFactorization::ClpFactorization()
  : CoinFactorization()
{
#ifndef SLIM_CLP
  networkBasis_ = NULL;
#endif
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpFactorization::ClpFactorization(const ClpFactorization &rhs,
  int dummyDenseIfSmaller)
  : CoinFactorization(rhs)
{
#ifndef SLIM_CLP
  if (rhs.networkBasis_)
    networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
  else
    networkBasis_ = NULL;
#endif
}

ClpFactorization::ClpFactorization(const CoinFactorization &rhs)
  : CoinFactorization(rhs)
{
#ifndef SLIM_CLP
  networkBasis_ = NULL;
#endif
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpFactorization::~ClpFactorization()
{
#ifndef SLIM_CLP
  delete networkBasis_;
#endif
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpFactorization &
ClpFactorization::operator=(const ClpFactorization &rhs)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
  if (this != &rhs) {
    CoinFactorization::operator=(rhs);
#ifndef SLIM_CLP
    delete networkBasis_;
    if (rhs.networkBasis_)
      networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
    else
      networkBasis_ = NULL;
#endif
  }
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(1);
#endif
  return *this;
}
#if 0
static unsigned int saveList[10000];
int numberSave = -1;
inline bool isDense(int i)
{
     return ((saveList[i>>5] >> (i & 31)) & 1) != 0;
}
inline void setDense(int i)
{
     unsigned int & value = saveList[i>>5];
     int bit = i & 31;
     value |= (1 << bit);
}
#endif
int ClpFactorization::factorize(ClpSimplex *model,
  int solveType, bool valuesPass)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
  ClpMatrixBase *matrix = model->clpMatrix();
  int numberRows = model->numberRows();
  int numberColumns = model->numberColumns();
  if (!numberRows)
    return 0;
  // If too many compressions increase area
  if (numberPivots_ > 1 && numberCompressions_ * 10 > numberPivots_ + 10) {
    areaFactor_ *= 1.1;
  }
  //int numberPivots=numberPivots_;
#if 0
     if (model->algorithm() > 0)
          numberSave = -1;
#endif
#ifndef SLIM_CLP
  if (!networkBasis_ || doCheck) {
#endif
    status_ = -99;
    int *pivotVariable = model->pivotVariable();
    //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
    while (status_ < -98) {

      int i;
      int numberBasic = 0;
      int numberRowBasic;
      // Move pivot variables across if they look good
      int *pivotTemp = model->rowArray(0)->getIndices();
      assert(!model->rowArray(0)->getNumElements());
      if (!matrix->rhsOffset(model)) {
#if 0
                    if (numberSave > 0) {
                         int nStill = 0;
                         int nAtBound = 0;
                         int nZeroDual = 0;
                         CoinIndexedVector * array = model->rowArray(3);
                         CoinIndexedVector * objArray = model->columnArray(1);
                         array->clear();
                         objArray->clear();
                         double * cost = model->costRegion();
                         double tolerance = model->primalTolerance();
                         double offset = 0.0;
                         for (i = 0; i < numberRows; i++) {
                              int iPivot = pivotVariable[i];
                              if (iPivot < numberColumns && isDense(iPivot)) {
                                   if (model->getColumnStatus(iPivot) == ClpSimplex::basic) {
                                        nStill++;
                                        double value = model->solutionRegion()[iPivot];
                                        double dual = model->dualRowSolution()[i];
                                        double lower = model->lowerRegion()[iPivot];
                                        double upper = model->upperRegion()[iPivot];
                                        ClpSimplex::Status status;
                                        if (fabs(value - lower) < tolerance) {
                                             status = ClpSimplex::atLowerBound;
                                             nAtBound++;
                                        } else if (fabs(value - upper) < tolerance) {
                                             nAtBound++;
                                             status = ClpSimplex::atUpperBound;
                                        } else if (value > lower && value < upper) {
                                             status = ClpSimplex::superBasic;
                                        } else {
                                             status = ClpSimplex::basic;
                                        }
                                        if (status != ClpSimplex::basic) {
                                             if (model->getRowStatus(i) != ClpSimplex::basic) {
                                                  model->setColumnStatus(iPivot, ClpSimplex::atLowerBound);
                                                  model->setRowStatus(i, ClpSimplex::basic);
                                                  pivotVariable[i] = i + numberColumns;
                                                  model->dualRowSolution()[i] = 0.0;
                                                  model->djRegion(0)[i] = 0.0;
                                                  array->add(i, dual);
                                                  offset += dual * model->solutionRegion(0)[i];
                                             }
                                        }
                                        if (fabs(dual) < 1.0e-5)
                                             nZeroDual++;
                                   }
                              }
                         }
                         printf("out of %d dense, %d still in basis, %d at bound, %d with zero dual - offset %g\n",
                                numberSave, nStill, nAtBound, nZeroDual, offset);
                         if (array->getNumElements()) {
                              // modify costs
                              model->clpMatrix()->transposeTimes(model, 1.0, array, model->columnArray(0),
                                                                 objArray);
                              array->clear();
                              int n = objArray->getNumElements();
                              int * indices = objArray->getIndices();
                              double * elements = objArray->denseVector();
                              for (i = 0; i < n; i++) {
                                   int iColumn = indices[i];
                                   cost[iColumn] -= elements[iColumn];
                                   elements[iColumn] = 0.0;
                              }
                              objArray->setNumElements(0);
                         }
                    }
#endif
        // Seems to prefer things in order so quickest
        // way is to go though like this
        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic)
            pivotTemp[numberBasic++] = i;
        }
        numberRowBasic = numberBasic;
        /* Put column basic variables into pivotVariable
                       This is done by ClpMatrixBase to allow override for gub
                    */
        matrix->generalExpanded(model, 0, numberBasic);
      } else {
        // Long matrix - do a different way
        bool fullSearch = false;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot >= numberColumns) {
            pivotTemp[numberBasic++] = iPivot - numberColumns;
          }
        }
        numberRowBasic = numberBasic;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot < numberColumns) {
            if (iPivot >= 0) {
              pivotTemp[numberBasic++] = iPivot;
            } else {
              // not full basis
              fullSearch = true;
              break;
            }
          }
        }
        if (fullSearch) {
          // do slow way
          numberBasic = 0;
          for (i = 0; i < numberRows; i++) {
            if (model->getRowStatus(i) == ClpSimplex::basic)
              pivotTemp[numberBasic++] = i;
          }
          numberRowBasic = numberBasic;
          /* Put column basic variables into pivotVariable
                            This is done by ClpMatrixBase to allow override for gub
                         */
          matrix->generalExpanded(model, 0, numberBasic);
        }
      }
      if (numberBasic > model->maximumBasic()) {
#if 0 // ndef NDEBUG
                    printf("%d basic - should only be %d\n",
                           numberBasic, numberRows);
#endif
        // Take out some
        numberBasic = numberRowBasic;
        for (int i = 0; i < numberColumns; i++) {
          if (model->getColumnStatus(i) == ClpSimplex::basic) {
            if (numberBasic < numberRows)
              numberBasic++;
            else
              model->setColumnStatus(i, ClpSimplex::superBasic);
          }
        }
        numberBasic = numberRowBasic;
        matrix->generalExpanded(model, 0, numberBasic);
      }
#ifndef SLIM_CLP
      // see if matrix a network
#ifndef NO_RTTI
      ClpNetworkMatrix *networkMatrix = dynamic_cast< ClpNetworkMatrix * >(model->clpMatrix());
#else
      ClpNetworkMatrix *networkMatrix = NULL;
      if (model->clpMatrix()->type() == 11)
        networkMatrix = static_cast< ClpNetworkMatrix * >(model->clpMatrix());
#endif
      // If network - still allow ordinary factorization first time for laziness
      if (networkMatrix)
        biasLU_ = 0; // All to U if network
      //int saveMaximumPivots = maximumPivots();
      delete networkBasis_;
      networkBasis_ = NULL;
      if (networkMatrix && !doCheck)
        maximumPivots(1);
#endif
      //printf("L, U, R %d %d %d\n",numberElementsL(),numberElementsU(),numberElementsR());
      while (status_ == -99) {
        // maybe for speed will be better to leave as many regions as possible
        gutsOfDestructor();
        gutsOfInitialize(2);
        CoinBigIndex numberElements = numberRowBasic;

        // compute how much in basis

        int i;
        // can change for gub
        int numberColumnBasic = numberBasic - numberRowBasic;

        numberElements += matrix->countBasis(model,
          pivotTemp + numberRowBasic,
          numberRowBasic,
          numberColumnBasic);
        // and recompute as network side say different
        if (model->numberIterations())
          numberRowBasic = numberBasic - numberColumnBasic;
        numberElements = 3 * numberBasic + 3 * numberElements + 20000;
#if 0
                    // If iteration not zero then may be compressed
                    getAreas ( !model->numberIterations() ? numberRows : numberBasic,
                               numberRowBasic + numberColumnBasic, numberElements,
                               2 * numberElements );
#else
      getAreas(numberRows,
        numberRowBasic + numberColumnBasic, numberElements,
        2 * numberElements);
#endif
        //fill
        // Fill in counts so we can skip part of preProcess
        int *numberInRow = numberInRow_.array();
        int *numberInColumn = numberInColumn_.array();
        CoinZeroN(numberInRow, numberRows_ + 1);
        CoinZeroN(numberInColumn, maximumColumnsExtra_ + 1);
        double *elementU = elementU_.array();
        int *indexRowU = indexRowU_.array();
        CoinBigIndex *startColumnU = startColumnU_.array();
        for (i = 0; i < numberRowBasic; i++) {
          int iRow = pivotTemp[i];
          indexRowU[i] = iRow;
          startColumnU[i] = i;
          elementU[i] = slackValue_;
          numberInRow[iRow] = 1;
          numberInColumn[i] = 1;
        }
        startColumnU[numberRowBasic] = numberRowBasic;
        // can change for gub so redo
        numberColumnBasic = numberBasic - numberRowBasic;
        matrix->fillBasis(model,
          pivotTemp + numberRowBasic,
          numberColumnBasic,
          indexRowU,
          startColumnU + numberRowBasic,
          numberInRow,
          numberInColumn + numberRowBasic,
          elementU);
#if 0
                    {
                         printf("%d row basic, %d column basic\n", numberRowBasic, numberColumnBasic);
                         for (int i = 0; i < numberElements; i++)
                              printf("row %d col %d value %g\n", indexRowU_.array()[i], indexColumnU_[i],
                                     elementU_.array()[i]);
                    }
#endif
        // recompute number basic
        numberBasic = numberRowBasic + numberColumnBasic;
        if (numberBasic)
          numberElements = startColumnU[numberBasic - 1]
            + numberInColumn[numberBasic - 1];
        else
          numberElements = 0;
        lengthU_ = numberElements;
        //saveFactorization("dump.d");
        if (biasLU_ >= 3 || numberRows_ != numberColumns_)
          preProcess(2);
        else
          preProcess(3); // no row copy
        factor();
        if (status_ == -99) {
          // get more memory
          areaFactor(2.0 * areaFactor());
        } else if (status_ == -1 && model->numberIterations() == 0 && denseThreshold_) {
          // Round again without dense
          denseThreshold_ = 0;
          status_ = -99;
        }
      }
      // If we get here status is 0 or -1
      if (status_ == 0) {
        // We may need to tamper with order and redo - e.g. network with side
        int useNumberRows = numberRows;
        // **** we will also need to add test in dual steepest to do
        // as we do for network
        matrix->generalExpanded(model, 12, useNumberRows);
        const int *permuteBack = permuteBack_.array();
        const int *back = pivotColumnBack_.array();
        //int * pivotTemp = pivotColumn_.array();
        //ClpDisjointCopyN ( pivotVariable, numberRows , pivotTemp  );
        // Redo pivot order
        for (i = 0; i < numberRowBasic; i++) {
          int k = pivotTemp[i];
          // so rowIsBasic[k] would be permuteBack[back[i]]
          pivotVariable[permuteBack[back[i]]] = k + numberColumns;
        }
        for (; i < useNumberRows; i++) {
          int k = pivotTemp[i];
          // so rowIsBasic[k] would be permuteBack[back[i]]
          pivotVariable[permuteBack[back[i]]] = k;
        }
#if 0
                    if (numberSave >= 0) {
                         numberSave = numberDense_;
                         memset(saveList, 0, ((numberRows_ + 31) >> 5)*sizeof(int));
                         for (i = numberRows_ - numberSave; i < numberRows_; i++) {
                              int k = pivotTemp[pivotColumn_.array()[i]];
                              setDense(k);
                         }
                    }
#endif
        // Set up permutation vector
        // these arrays start off as copies of permute
        // (and we could use permute_ instead of pivotColumn (not back though))
        ClpDisjointCopyN(permute_.array(), useNumberRows, pivotColumn_.array());
        ClpDisjointCopyN(permuteBack_.array(), useNumberRows, pivotColumnBack_.array());
#ifndef SLIM_CLP
        if (networkMatrix) {
          maximumPivots(CoinMax(2000, maximumPivots()));
          // redo arrays
          for (int iRow = 0; iRow < 4; iRow++) {
            int length = model->numberRows() + maximumPivots();
            if (iRow == 3 || model->objectiveAsObject()->type() > 1)
              length += model->numberColumns();
            model->rowArray(iRow)->reserve(length);
          }
          // create network factorization
          if (doCheck)
            delete networkBasis_; // temp
          networkBasis_ = new ClpNetworkBasis(model, numberRows_,
            pivotRegion_.array(),
            permuteBack_.array(),
            startColumnU_.array(),
            numberInColumn_.array(),
            indexRowU_.array(),
            elementU_.array());
          // kill off arrays in ordinary factorization
          if (!doCheck) {
            gutsOfDestructor();
            // but make sure numberRows_ set
            numberRows_ = model->numberRows();
            status_ = 0;
#if 0
                              // but put back permute arrays so odd things will work
                              int numberRows = model->numberRows();
                              pivotColumnBack_ = new int [numberRows];
                              permute_ = new int [numberRows];
                              int i;
                              for (i = 0; i < numberRows; i++) {
                                   pivotColumnBack_[i] = i;
                                   permute_[i] = i;
                              }
#endif
          }
        } else {
#endif
          // See if worth going sparse and when
          if (numberFtranCounts_ > 100) {
            ftranCountInput_ = CoinMax(ftranCountInput_, 1.0);
            ftranAverageAfterL_ = CoinMax(ftranCountAfterL_ / ftranCountInput_, 1.0);
            ftranAverageAfterR_ = CoinMax(ftranCountAfterR_ / ftranCountAfterL_, 1.0);
            ftranAverageAfterU_ = CoinMax(ftranCountAfterU_ / ftranCountAfterR_, 1.0);
            if (btranCountInput_ && btranCountAfterU_ && btranCountAfterR_) {
              btranAverageAfterU_ = CoinMax(btranCountAfterU_ / btranCountInput_, 1.0);
              btranAverageAfterR_ = CoinMax(btranCountAfterR_ / btranCountAfterU_, 1.0);
              btranAverageAfterL_ = CoinMax(btranCountAfterL_ / btranCountAfterR_, 1.0);
            } else {
              // we have not done any useful btrans (values pass?)
              btranAverageAfterU_ = 1.0;
              btranAverageAfterR_ = 1.0;
              btranAverageAfterL_ = 1.0;
            }
          }
          // scale back

          ftranCountInput_ *= 0.8;
          ftranCountAfterL_ *= 0.8;
          ftranCountAfterR_ *= 0.8;
          ftranCountAfterU_ *= 0.8;
          btranCountInput_ *= 0.8;
          btranCountAfterU_ *= 0.8;
          btranCountAfterR_ *= 0.8;
          btranCountAfterL_ *= 0.8;
#ifndef SLIM_CLP
        }
#endif
      } else if (status_ == -1 && (solveType == 0 || solveType == 2)) {
        // This needs redoing as it was merged coding - does not need array
        int numberTotal = numberRows + numberColumns;
        int *isBasic = new int[numberTotal];
        int *rowIsBasic = isBasic + numberColumns;
        int *columnIsBasic = isBasic;
        for (i = 0; i < numberTotal; i++)
          isBasic[i] = -1;
        for (i = 0; i < numberRowBasic; i++) {
          int iRow = pivotTemp[i];
          rowIsBasic[iRow] = 1;
        }
        for (; i < numberBasic; i++) {
          int iColumn = pivotTemp[i];
          columnIsBasic[iColumn] = 1;
        }
        numberBasic = 0;
        for (i = 0; i < numberRows; i++)
          pivotVariable[i] = -1;
        // mark as basic or non basic
        const int *pivotColumn = pivotColumn_.array();
        for (i = 0; i < numberRows; i++) {
          if (rowIsBasic[i] >= 0) {
            if (pivotColumn[numberBasic] >= 0) {
              rowIsBasic[i] = pivotColumn[numberBasic];
            } else {
              rowIsBasic[i] = -1;
              model->setRowStatus(i, ClpSimplex::superBasic);
            }
            numberBasic++;
          }
        }
        for (i = 0; i < numberColumns; i++) {
          if (columnIsBasic[i] >= 0) {
            if (pivotColumn[numberBasic] >= 0)
              columnIsBasic[i] = pivotColumn[numberBasic];
            else
              columnIsBasic[i] = -1;
            numberBasic++;
          }
        }
        // leave pivotVariable in useful form for cleaning basis
        int *pivotVariable = model->pivotVariable();
        for (i = 0; i < numberRows; i++) {
          pivotVariable[i] = -1;
        }

        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic) {
            int iPivot = rowIsBasic[i];
            if (iPivot >= 0)
              pivotVariable[iPivot] = i + numberColumns;
          }
        }
        for (i = 0; i < numberColumns; i++) {
          if (model->getColumnStatus(i) == ClpSimplex::basic) {
            int iPivot = columnIsBasic[i];
            if (iPivot >= 0)
              pivotVariable[iPivot] = i;
          }
        }
        delete[] isBasic;
        double *columnLower = model->lowerRegion();
        double *columnUpper = model->upperRegion();
        double *columnActivity = model->solutionRegion();
        double *rowLower = model->lowerRegion(0);
        double *rowUpper = model->upperRegion(0);
        double *rowActivity = model->solutionRegion(0);
        //redo basis - first take ALL columns out
        int iColumn;
        double largeValue = model->largeValue();
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
            // take out
            if (!valuesPass) {
              double lower = columnLower[iColumn];
              double upper = columnUpper[iColumn];
              double value = columnActivity[iColumn];
              if (lower > -largeValue || upper < largeValue) {
                if (fabs(value - lower) < fabs(value - upper)) {
                  model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
                  columnActivity[iColumn] = lower;
                } else {
                  model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
                  columnActivity[iColumn] = upper;
                }
              } else {
                model->setColumnStatus(iColumn, ClpSimplex::isFree);
              }
            } else {
              model->setColumnStatus(iColumn, ClpSimplex::superBasic);
            }
          }
        }
        int iRow;
        for (iRow = 0; iRow < numberRows; iRow++) {
          int iSequence = pivotVariable[iRow];
          if (iSequence >= 0) {
            // basic
            if (iSequence >= numberColumns) {
              // slack in - leave
              //assert (iSequence-numberColumns==iRow);
            } else {
              assert(model->getRowStatus(iRow) != ClpSimplex::basic);
              // put back structural
              model->setColumnStatus(iSequence, ClpSimplex::basic);
            }
          } else {
            // put in slack
            model->setRowStatus(iRow, ClpSimplex::basic);
          }
        }
        // Put back any key variables for gub (status_ not touched)
        matrix->generalExpanded(model, 1, status_);
        // signal repeat
        status_ = -99;
        // set fixed if they are
        for (iRow = 0; iRow < numberRows; iRow++) {
          if (model->getRowStatus(iRow) != ClpSimplex::basic) {
            if (rowLower[iRow] == rowUpper[iRow]) {
              rowActivity[iRow] = rowLower[iRow];
              model->setRowStatus(iRow, ClpSimplex::isFixed);
            }
          }
        }
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) != ClpSimplex::basic) {
            if (columnLower[iColumn] == columnUpper[iColumn]) {
              columnActivity[iColumn] = columnLower[iColumn];
              model->setColumnStatus(iColumn, ClpSimplex::isFixed);
            }
          }
        }
      }
    }
#ifndef SLIM_CLP
  } else {
    // network - fake factorization - do nothing
    status_ = 0;
    numberPivots_ = 0;
  }
#endif
#ifndef SLIM_CLP
  if (!status_) {
    // take out part if quadratic
    if (model->algorithm() == 2) {
      ClpObjective *obj = model->objectiveAsObject();
#ifndef NDEBUG
      ClpQuadraticObjective *quadraticObj = (dynamic_cast< ClpQuadraticObjective * >(obj));
      assert(quadraticObj);
#else
      ClpQuadraticObjective *quadraticObj = (static_cast< ClpQuadraticObjective * >(obj));
#endif
      CoinPackedMatrix *quadratic = quadraticObj->quadraticObjective();
      int numberXColumns = quadratic->getNumCols();
      assert(numberXColumns < numberColumns);
      int base = numberColumns - numberXColumns;
      int *which = new int[numberXColumns];
      int *pivotVariable = model->pivotVariable();
      int *permute = pivotColumn();
      int i;
      int n = 0;
      for (i = 0; i < numberRows; i++) {
        int iSj = pivotVariable[i] - base;
        if (iSj >= 0 && iSj < numberXColumns)
          which[n++] = permute[i];
      }
      if (n)
        emptyRows(n, which);
      delete[] which;
    }
  }
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(2);
#endif
  return status_;
}
/* Replaces one Column to basis,
   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
   If checkBeforeModifying is true will do all accuracy checks
   before modifying factorization.  Whether to set this depends on
   speed considerations.  You could just do this on first iteration
   after factorization and thereafter re-factorize
   partial update already in U */
int ClpFactorization::replaceColumn(const ClpSimplex *model,
  CoinIndexedVector *regionSparse,
  CoinIndexedVector *tableauColumn,
  int pivotRow,
  double pivotCheck,
  bool checkBeforeModifying,
  double acceptablePivot)
{
  int returnCode;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    // see if FT
    if (doForrestTomlin_) {
      returnCode = CoinFactorization::replaceColumn(regionSparse,
        pivotRow,
        pivotCheck,
        checkBeforeModifying,
        acceptablePivot);
    } else {
      returnCode = CoinFactorization::replaceColumnPFI(tableauColumn,
        pivotRow, pivotCheck); // Note array
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(3);
#endif

#ifndef SLIM_CLP
  } else {
    if (doCheck) {
      returnCode = CoinFactorization::replaceColumn(regionSparse,
        pivotRow,
        pivotCheck,
        checkBeforeModifying,
        acceptablePivot);
      networkBasis_->replaceColumn(regionSparse,
        pivotRow);
    } else {
      // increase number of pivots
      numberPivots_++;
      returnCode = networkBasis_->replaceColumn(regionSparse,
        pivotRow);
    }
  }
#endif
  return returnCode;
}

/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnFT(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2)
{
#ifdef CLP_DEBUG
  regionSparse->checkClear();
#endif
  if (!numberRows_)
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    collectStatistics_ = true;
    int returnCode = CoinFactorization::updateColumnFT(regionSparse,
      regionSparse2);
    collectStatistics_ = false;
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(4);
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[numberRows_];
    int returnCode = CoinFactorization::updateColumnFT(regionSparse,
      regionSparse2);
    networkBasis_->updateColumn(regionSparse, save, -1);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, numberRows_ * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      for (i = 0; i < numberRows_; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
    return 1;
#endif
  }
#endif
}
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumn(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  bool noPermute) const
{
#ifdef CLP_DEBUG
  if (!noPermute)
    regionSparse->checkClear();
#endif
  if (!numberRows_)
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    collectStatistics_ = true;
    int returnCode = CoinFactorization::updateColumn(regionSparse,
      regionSparse2,
      noPermute);
    collectStatistics_ = false;
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(5);
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[numberRows_];
    int returnCode = CoinFactorization::updateColumn(regionSparse,
      regionSparse2,
      noPermute);
    networkBasis_->updateColumn(regionSparse, save, -1);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, numberRows_ * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      for (i = 0; i < numberRows_; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
    return 1;
#endif
  }
#endif
}
/* Updates one column (FTRAN) from region2
   Tries to do FT update
   number returned is negative if no room.
   Also updates region3
   region1 starts as zero and is zero at end */
int ClpFactorization::updateTwoColumnsFT(CoinIndexedVector *regionSparse1,
  CoinIndexedVector *regionSparse2,
  CoinIndexedVector *regionSparse3,
  bool noPermuteRegion3)
{
  int returnCode = updateColumnFT(regionSparse1, regionSparse2);
  updateColumn(regionSparse1, regionSparse3, noPermuteRegion3);
  return returnCode;
}
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnForDebug(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  bool noPermute) const
{
  if (!noPermute)
    regionSparse->checkClear();
  if (!numberRows_)
    return 0;
  collectStatistics_ = false;
  int returnCode = CoinFactorization::updateColumn(regionSparse,
    regionSparse2,
    noPermute);
  return returnCode;
}
/* Updates one column (BTRAN) from region2
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnTranspose(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2) const
{
  if (!numberRows_)
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    collectStatistics_ = true;
    int returnCode = CoinFactorization::updateColumnTranspose(regionSparse,
      regionSparse2);
    collectStatistics_ = false;
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(6);
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[numberRows_];
    int returnCode = CoinFactorization::updateColumnTranspose(regionSparse,
      regionSparse2);
    networkBasis_->updateColumnTranspose(regionSparse, save);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, numberRows_ * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      for (i = 0; i < numberRows_; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    return networkBasis_->updateColumnTranspose(regionSparse, regionSparse2);
#endif
  }
#endif
}
/* Updates two columns (BTRAN) from regionSparse2 and 3
   regionSparse starts as zero and is zero at end 
   Note - if regionSparse2 packed on input - will be packed on output - same for 3
*/
void ClpFactorization::updateTwoColumnsTranspose(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  CoinIndexedVector *regionSparse3) const
{
  if (!numberRows_)
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    collectStatistics_ = true;
    CoinFactorization::updateTwoColumnsTranspose(regionSparse,
      regionSparse2, regionSparse3);
    collectStatistics_ = false;
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(6);
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
    factorization__->updateColumnTranspose(regionSparse, regionSparse2);
    factorization__->updateColumnTranspose(regionSparse, regionSparse3);
  }
#endif
}
/* makes a row copy of L for speed and to allow very sparse problems */
void ClpFactorization::goSparse()
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  if (!networkBasis_)
#endif
    CoinFactorization::goSparse();
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(7);
#endif
}
// Cleans up i.e. gets rid of network basis
void ClpFactorization::cleanUp()
{
#ifndef SLIM_CLP
  delete networkBasis_;
  networkBasis_ = NULL;
#endif
  resetStatistics();
}
/// Says whether to redo pivot order
bool ClpFactorization::needToReorder() const
{
#ifdef CHECK_NETWORK
  return true;
#endif
#ifndef SLIM_CLP
  if (!networkBasis_)
#endif
    return true;
#ifndef SLIM_CLP
  else
    return false;
#endif
}
// Get weighted row list
void ClpFactorization::getWeights(int *weights) const
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  if (networkBasis_) {
    // Network - just unit
    for (int i = 0; i < numberRows_; i++)
      weights[i] = 1;
    return;
  }
#endif
  int *numberInRow = numberInRow_.array();
  int *numberInColumn = numberInColumn_.array();
  int *permuteBack = pivotColumnBack_.array();
  int *indexRowU = indexRowU_.array();
  const CoinBigIndex *startColumnU = startColumnU_.array();
  const CoinBigIndex *startRowL = startRowL_.array();
  if (!startRowL || !numberInRow_.array()) {
    int *temp = new int[numberRows_];
    memset(temp, 0, numberRows_ * sizeof(int));
    int i;
    for (i = 0; i < numberRows_; i++) {
      // one for pivot
      temp[i]++;
      CoinBigIndex j;
      for (j = startColumnU[i]; j < startColumnU[i] + numberInColumn[i]; j++) {
        int iRow = indexRowU[j];
        temp[iRow]++;
      }
    }
    CoinBigIndex *startColumnL = startColumnL_.array();
    int *indexRowL = indexRowL_.array();
    for (i = baseL_; i < baseL_ + numberL_; i++) {
      CoinBigIndex j;
      for (j = startColumnL[i]; j < startColumnL[i + 1]; j++) {
        int iRow = indexRowL[j];
        temp[iRow]++;
      }
    }
    for (i = 0; i < numberRows_; i++) {
      int number = temp[i];
      int iPermute = permuteBack[i];
      weights[iPermute] = number;
    }
    delete[] temp;
  } else {
    int i;
    for (i = 0; i < numberRows_; i++) {
      int number = startRowL[i + 1] - startRowL[i] + numberInRow[i] + 1;
      //number = startRowL[i+1]-startRowL[i]+1;
      //number = numberInRow[i]+1;
      int iPermute = permuteBack[i];
      weights[iPermute] = number;
    }
  }
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(8);
#endif
}
#else
#if COIN_BIG_INDEX == 0
// This one allows multiple factorizations
#if CLP_MULTIPLE_FACTORIZATIONS == 1
typedef CoinDenseFactorization CoinOtherFactorization;
typedef CoinOslFactorization CoinOtherFactorization;
#elif CLP_MULTIPLE_FACTORIZATIONS == 2
#include "CoinSimpFactorization.hpp"
typedef CoinSimpFactorization CoinOtherFactorization;
typedef CoinOslFactorization CoinOtherFactorization;
#elif CLP_MULTIPLE_FACTORIZATIONS == 3
#include "CoinSimpFactorization.hpp"
#define CoinOslFactorization CoinDenseFactorization
#elif CLP_MULTIPLE_FACTORIZATIONS == 4
#include "CoinSimpFactorization.hpp"
//#define CoinOslFactorization CoinDenseFactorization
#include "CoinOslFactorization.hpp"
#endif
#endif

//-------------------------------------------------------------------
// Default Constructor
//-------------------------------------------------------------------
ClpFactorization::ClpFactorization()
{
#ifndef SLIM_CLP
  networkBasis_ = NULL;
#endif
  //coinFactorizationA_ = NULL;
  coinFactorizationA_ = new CoinFactorization();
  coinFactorizationB_ = NULL;
  //coinFactorizationB_ = new CoinOtherFactorization();
  forceB_ = 0;
  goOslThreshold_ = -1;
  goDenseThreshold_ = -1;
  goSmallThreshold_ = -1;
  doStatistics_ = true;
  memset(&shortestAverage_, 0, 3 * (sizeof(double) + sizeof(int)));
}

//-------------------------------------------------------------------
// Copy constructor
//-------------------------------------------------------------------
ClpFactorization::ClpFactorization(const ClpFactorization &rhs,
  int denseIfSmaller)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  if (rhs.networkBasis_)
    networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
  else
    networkBasis_ = NULL;
#endif
  forceB_ = rhs.forceB_;
  goOslThreshold_ = rhs.goOslThreshold_;
  goDenseThreshold_ = rhs.goDenseThreshold_;
  goSmallThreshold_ = rhs.goSmallThreshold_;
  doStatistics_ = rhs.doStatistics_;
  int goDense = 0;
#ifdef CLP_REUSE_ETAS
  model_ = rhs.model_;
#endif
#if COIN_BIG_INDEX == 0
  if (denseIfSmaller > 0 && denseIfSmaller <= goDenseThreshold_) {
    CoinDenseFactorization *denseR = dynamic_cast< CoinDenseFactorization * >(rhs.coinFactorizationB_);
    if (!denseR)
      goDense = 1;
  }
  if (denseIfSmaller > 0 && !rhs.coinFactorizationB_) {
    if (denseIfSmaller <= goDenseThreshold_)
      goDense = 1;
    else if (denseIfSmaller <= goSmallThreshold_)
      goDense = 2;
    else if (denseIfSmaller <= goOslThreshold_)
      goDense = 3;
  } else if (denseIfSmaller < 0) {
    if (-denseIfSmaller <= goDenseThreshold_)
      goDense = 1;
    else if (-denseIfSmaller <= goSmallThreshold_)
      goDense = 2;
    else if (-denseIfSmaller <= goOslThreshold_)
      goDense = 3;
  }
#endif
  if (rhs.coinFactorizationA_ && !goDense)
    coinFactorizationA_ = new CoinFactorization(*(rhs.coinFactorizationA_));
  else
    coinFactorizationA_ = NULL;
  if (rhs.coinFactorizationB_ && (denseIfSmaller >= 0 || !goDense))
    coinFactorizationB_ = rhs.coinFactorizationB_->clone();
  else
    coinFactorizationB_ = NULL;
#if COIN_BIG_INDEX == 0
  if (goDense) {
    delete coinFactorizationB_;
    if (goDense == 1)
      coinFactorizationB_ = new CoinDenseFactorization();
    else if (goDense == 2)
      coinFactorizationB_ = new CoinSimpFactorization();
    else
      coinFactorizationB_ = new CoinOslFactorization();
    if (rhs.coinFactorizationA_) {
      coinFactorizationB_->maximumPivots(rhs.coinFactorizationA_->maximumPivots());
      coinFactorizationB_->pivotTolerance(rhs.coinFactorizationA_->pivotTolerance());
      coinFactorizationB_->zeroTolerance(rhs.coinFactorizationA_->zeroTolerance());
    } else {
      assert(coinFactorizationB_);
      coinFactorizationB_->maximumPivots(rhs.coinFactorizationB_->maximumPivots());
      coinFactorizationB_->pivotTolerance(rhs.coinFactorizationB_->pivotTolerance());
      coinFactorizationB_->zeroTolerance(rhs.coinFactorizationB_->zeroTolerance());
    }
  }
#endif
  assert(!coinFactorizationA_ || !coinFactorizationB_);
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(1);
#endif
  memcpy(&shortestAverage_, &rhs.shortestAverage_, 3 * (sizeof(double) + sizeof(int)));
}

ClpFactorization::ClpFactorization(const CoinFactorization &rhs)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  networkBasis_ = NULL;
#endif
  coinFactorizationA_ = new CoinFactorization(rhs);
  coinFactorizationB_ = NULL;
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(1);
#endif
  forceB_ = 0;
  goOslThreshold_ = -1;
  goDenseThreshold_ = -1;
  goSmallThreshold_ = -1;
  doStatistics_ = true;
  assert(!coinFactorizationA_ || !coinFactorizationB_);
  memset(&shortestAverage_, 0, 3 * (sizeof(double) + sizeof(int)));
}

ClpFactorization::ClpFactorization(const CoinOtherFactorization &rhs)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  networkBasis_ = NULL;
#endif
  coinFactorizationA_ = NULL;
  coinFactorizationB_ = rhs.clone();
  //coinFactorizationB_ = new CoinOtherFactorization(rhs);
  forceB_ = 0;
  goOslThreshold_ = -1;
  goDenseThreshold_ = -1;
  goSmallThreshold_ = -1;
  doStatistics_ = true;
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(1);
#endif
  assert(!coinFactorizationA_ || !coinFactorizationB_);
  memset(&shortestAverage_, 0, 3 * (sizeof(double) + sizeof(int)));
}

//-------------------------------------------------------------------
// Destructor
//-------------------------------------------------------------------
ClpFactorization::~ClpFactorization()
{
#ifndef SLIM_CLP
  delete networkBasis_;
#endif
  delete coinFactorizationA_;
  delete coinFactorizationB_;
}

//----------------------------------------------------------------
// Assignment operator
//-------------------------------------------------------------------
ClpFactorization &
ClpFactorization::operator=(const ClpFactorization &rhs)
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
  if (this != &rhs) {
#ifndef SLIM_CLP
    delete networkBasis_;
    if (rhs.networkBasis_)
      networkBasis_ = new ClpNetworkBasis(*(rhs.networkBasis_));
    else
      networkBasis_ = NULL;
#endif
    forceB_ = rhs.forceB_;
#ifdef CLP_REUSE_ETAS
    model_ = rhs.model_;
#endif
    goOslThreshold_ = rhs.goOslThreshold_;
    goDenseThreshold_ = rhs.goDenseThreshold_;
    goSmallThreshold_ = rhs.goSmallThreshold_;
    doStatistics_ = rhs.doStatistics_;
    memcpy(&shortestAverage_, &rhs.shortestAverage_, 3 * (sizeof(double) + sizeof(int)));
    if (rhs.coinFactorizationA_) {
      if (coinFactorizationA_)
        *coinFactorizationA_ = *(rhs.coinFactorizationA_);
      else
        coinFactorizationA_ = new CoinFactorization(*rhs.coinFactorizationA_);
    } else {
      delete coinFactorizationA_;
      coinFactorizationA_ = NULL;
    }
#if COIN_BIG_INDEX == 0
    if (rhs.coinFactorizationB_) {
      if (coinFactorizationB_) {
        CoinDenseFactorization *denseR = dynamic_cast< CoinDenseFactorization * >(rhs.coinFactorizationB_);
        CoinDenseFactorization *dense = dynamic_cast< CoinDenseFactorization * >(coinFactorizationB_);
        CoinOslFactorization *oslR = dynamic_cast< CoinOslFactorization * >(rhs.coinFactorizationB_);
        CoinOslFactorization *osl = dynamic_cast< CoinOslFactorization * >(coinFactorizationB_);
        CoinSimpFactorization *simpR = dynamic_cast< CoinSimpFactorization * >(rhs.coinFactorizationB_);
        CoinSimpFactorization *simp = dynamic_cast< CoinSimpFactorization * >(coinFactorizationB_);
        if (dense && denseR) {
          *dense = *denseR;
        } else if (osl && oslR) {
          *osl = *oslR;
        } else if (simp && simpR) {
          *simp = *simpR;
        } else {
          delete coinFactorizationB_;
          coinFactorizationB_ = rhs.coinFactorizationB_->clone();
        }
      } else {
        coinFactorizationB_ = rhs.coinFactorizationB_->clone();
      }
    } else {
      delete coinFactorizationB_;
      coinFactorizationB_ = NULL;
    }
#endif
  }
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(1);
#endif
  assert(!coinFactorizationA_ || !coinFactorizationB_);
  return *this;
}
// Go over to dense code
void ClpFactorization::goDenseOrSmall(int numberRows)
{
  if (!forceB_) {
    if (numberRows <= goDenseThreshold_) {
      delete coinFactorizationA_;
      delete coinFactorizationB_;
      coinFactorizationA_ = NULL;
      coinFactorizationB_ = new CoinDenseFactorization();
      //printf("going dense\n");
#if COIN_BIG_INDEX == 0
    } else if (numberRows <= goSmallThreshold_) {
      delete coinFactorizationA_;
      delete coinFactorizationB_;
      coinFactorizationA_ = NULL;
      coinFactorizationB_ = new CoinSimpFactorization();
      //printf("going small\n");
    } else if (numberRows <= goOslThreshold_) {
      delete coinFactorizationA_;
      delete coinFactorizationB_;
      coinFactorizationA_ = NULL;
      coinFactorizationB_ = new CoinOslFactorization();
      //printf("going small\n");
#endif
    }
  }
  assert(!coinFactorizationA_ || !coinFactorizationB_);
}
// If nonzero force use of 1,dense 2,small 3,osl
void ClpFactorization::forceOtherFactorization(int which)
{
  delete coinFactorizationB_;
  forceB_ = 0;
  coinFactorizationB_ = NULL;
  if (which > 0 && which < 4) {
    delete coinFactorizationA_;
    coinFactorizationA_ = NULL;
    forceB_ = which;
    switch (which) {
    case 1:
      coinFactorizationB_ = new CoinDenseFactorization();
      goDenseThreshold_ = COIN_INT_MAX;
      break;
#if COIN_BIG_INDEX == 0
    case 2:
      coinFactorizationB_ = new CoinSimpFactorization();
      goSmallThreshold_ = COIN_INT_MAX;
      break;
    case 3:
      coinFactorizationB_ = new CoinOslFactorization();
      goOslThreshold_ = COIN_INT_MAX;
      break;
#endif
    }
  } else if (!coinFactorizationA_) {
    coinFactorizationA_ = new CoinFactorization();
    goOslThreshold_ = -1;
    goDenseThreshold_ = -1;
    goSmallThreshold_ = -1;
  }
}
#ifdef CLP_FACTORIZATION_NEW_TIMING
#ifdef CLP_FACTORIZATION_INSTRUMENT
extern double externalTimeStart;
extern double timeInFactorize;
extern double timeInUpdate;
extern double timeInFactorizeFake;
extern double timeInUpdateFake1;
extern double timeInUpdateFake2;
extern double timeInUpdateTranspose;
extern double timeInUpdateFT;
extern double timeInUpdateTwoFT;
extern double timeInReplace;
extern int numberUpdate;
extern int numberUpdateTranspose;
extern int numberUpdateFT;
extern int numberUpdateTwoFT;
extern int numberReplace;
extern int currentLengthR;
extern int currentLengthU;
extern int currentTakeoutU;
extern double averageLengthR;
extern double averageLengthL;
extern double averageLengthU;
extern double scaledLengthDense;
extern double scaledLengthDenseSquared;
extern double scaledLengthL;
extern double scaledLengthR;
extern double scaledLengthU;
extern int startLengthU;
extern int endLengthU;
extern int endLengthU2;
extern int numberAdded;
static int average[3];
static double shortest;
static int ifPrint;
#else
#ifdef CLP_STATIC
static int endLengthU_;
#endif
#endif
#ifdef CLP_STATIC
static double shortestAverage_;
static double totalInR_ = 0.0;
static double totalInIncreasingU_ = 0.0;
//static int lastR=0;
//static int lastU=0;
static int lastNumberPivots_ = 0;
static int effectiveStartNumberU_ = 0;
#else
//#define shortestAverage shortestAverage_
//#define totalInR totalInR_
//#define totalInIncreasingU totalInIncreasingU_
//#define lastNumberPivots lastNumberPivots_
//#define effectiveStartNumberU effectiveStartNumberU_
//#define endLengthU endLengthU_
#endif
#ifdef CLP_USEFUL_PRINTOUT
static bool readTwiddle = false;
static double weightIncU = 1.0;
static double weightR = 2.0;
static double weightRest = 1.0;
static double weightFactL = 30.0;
static double weightFactDense = 0.1;
static double weightNrows = 10.0;
static double increaseNeeded = 1.1;
static double constWeightIterate = 1.0;
static double weightNrowsIterate = 3.0;
#else
#define weightIncU 1.0
#define weightR 2.0
#define weightRest 1.0
#define weightFactL 30.0
#define weightFactDense 0.1
#define weightNrows 10.0
#define increaseNeeded 1.1
#define constWeightIterate 1.0
#define weightNrowsIterate 3.0
#endif
bool ClpFactorization::timeToRefactorize() const
{
  if (coinFactorizationA_) {
    bool reFactor = (coinFactorizationA_->pivots() * 3 > coinFactorizationA_->maximumPivots() * 2 && coinFactorizationA_->numberElementsR() * 3 > (coinFactorizationA_->numberElementsL() + coinFactorizationA_->numberElementsU()) * 2 + 1000 && !coinFactorizationA_->numberDense());
    reFactor = false;
    bool reFactor3 = false;
    int numberPivots = coinFactorizationA_->pivots();
    //if (coinFactorizationA_->pivots()<2)
    if (numberPivots > lastNumberPivots_) {
      if (!lastNumberPivots_) {
        //lastR=0;
        //lastU=endLengthU;
        totalInR_ = 0.0;
        totalInIncreasingU_ = 0.0;
        shortestAverage_ = COIN_DBL_MAX;
#ifdef CLP_USEFUL_PRINTOUT
        if (!readTwiddle) {
          readTwiddle = true;
          char *environ = getenv("CLP_TWIDDLE");
          if (environ) {
            sscanf(environ, "%lg %lg %lg %lg %lg %lg %lg %lg %lg",
              &weightIncU, &weightR, &weightRest, &weightFactL,
              &weightFactDense, &weightNrows, &increaseNeeded,
              &constWeightIterate, &weightNrowsIterate);
          }
          printf("weightIncU %g, weightR %g, weightRest %g, weightFactL %g, weightFactDense %g, weightNrows %g increaseNeeded %g constWeightIterate %g weightNrowsIterate %g\n",
            weightIncU, weightR, weightRest, weightFactL,
            weightFactDense, weightNrows, increaseNeeded,
            constWeightIterate, weightNrowsIterate);
        }
#endif
      }
      lastNumberPivots_ = numberPivots;
      int numberDense = coinFactorizationA_->numberDense();
      double nnd = numberDense * numberDense;
      int lengthL = coinFactorizationA_->numberElementsL();
      int lengthR = coinFactorizationA_->numberElementsR();
      int numberRows = coinFactorizationA_->numberRows();
      int lengthU = coinFactorizationA_->numberElementsU() - (numberRows - numberDense);
      totalInR_ += lengthR;
      int effectiveU = lengthU - effectiveStartNumberU_;
      totalInIncreasingU_ += effectiveU;
      //lastR=lengthR;
      //lastU=lengthU;
      double rest = lengthL + 0.05 * nnd;
      double constWeightFactor = weightFactL * lengthL + weightFactDense * nnd
        + weightNrows * numberRows;
      double constWeightIterateX = constWeightIterate * (lengthL + endLengthU_)
        + weightNrowsIterate * numberRows;
      double variableWeight = weightIncU * totalInIncreasingU_ + weightR * totalInR_ + weightRest * rest;
      double average = constWeightIterateX + (constWeightFactor + variableWeight) / static_cast< double >(numberPivots);
#if 0
      if ((numberPivots%20)==0&&!ifPrint3)
      printf("PIV %d nrow %d startU %d now %d L %d R %d dense %g average %g\n",
      numberPivots,numberRows,effectiveStartNumberU_,
      lengthU,lengthL,lengthR,nnd,average);
#endif
      shortestAverage_ = CoinMin(shortestAverage_, average);
      if (average > increaseNeeded * shortestAverage_ && coinFactorizationA_->pivots() > 30) {
        //printf("PIVX %d nrow %d startU %d now %d L %d R %d dense %g average %g\n",
        //numberPivots,numberRows,effectiveStartNumberU_,
        //lengthU,lengthL,lengthR,nnd,average);
        reFactor3 = true;
      }
    }
    if (reFactor || reFactor3) {
#if 0
	printf("%c%cftranCountInput_ %g  ,ftranCountAfterL_ %g  ,ftranCountAfterR_ %g  ,ftranCountAfterU_ %g  ,btranCountInput_ %g  ,btranCountAfterU_ %g  ,btranCountAfterR_ %g  ,btranCountAfterL_ %g  ,numberFtranCounts_ %d  ,numberBtranCounts_ %d  ,ftranAverageAfterL_ %g  ,ftranAverageAfterR_ %g  ,ftranAverageAfterU_ %g  ,btranAverageAfterU_ %g  ,btranAverageAfterR_ %g  ,btranAverageAfterL_ %g\n"
	       ,reFactor3 ? 'Y' : 'N'
	       ,reFactor ? 'Y' : 'N'
  ,coinFactorizationA_->ftranCountInput_
  ,coinFactorizationA_->ftranCountAfterL_
  ,coinFactorizationA_->ftranCountAfterR_
  ,coinFactorizationA_->ftranCountAfterU_
  ,coinFactorizationA_->btranCountInput_
  ,coinFactorizationA_->btranCountAfterU_
  ,coinFactorizationA_->btranCountAfterR_
  ,coinFactorizationA_->btranCountAfterL_
  ,coinFactorizationA_->numberFtranCounts_
  ,coinFactorizationA_->numberBtranCounts_
  ,coinFactorizationA_->ftranAverageAfterL_
  ,coinFactorizationA_->ftranAverageAfterR_
  ,coinFactorizationA_->ftranAverageAfterU_
  ,coinFactorizationA_->btranAverageAfterU_
  ,coinFactorizationA_->btranAverageAfterR_
	       ,coinFactorizationA_->btranAverageAfterL_);
#endif
      reFactor = true;
    }
    return reFactor;
  } else {
    return coinFactorizationB_->pivots() > coinFactorizationB_->numberRows() / 2.45 + 20;
  }
}
#if CLP_FACTORIZATION_NEW_TIMING > 1
void ClpFactorization::statsRefactor(char when) const
{
  int numberPivots = coinFactorizationA_->pivots();
  int numberDense = coinFactorizationA_->numberDense();
  double nnd = numberDense * numberDense;
  int lengthL = coinFactorizationA_->numberElementsL();
  int lengthR = coinFactorizationA_->numberElementsR();
  int numberRows = coinFactorizationA_->numberRows();
  int lengthU = coinFactorizationA_->numberElementsU() - (numberRows - numberDense);
  double rest = lengthL + 0.05 * nnd;
  double constWeightFactor = weightFactL * lengthL + weightFactDense * nnd
    + weightNrows * numberRows;
  double constWeightIterateX = constWeightIterate * (lengthL + endLengthU_)
    + weightNrowsIterate * numberRows;
  double variableWeight = weightIncU * totalInIncreasingU_ + weightR * totalInR_ + weightRest * rest;
  double average = constWeightIterateX + (constWeightFactor + variableWeight) / static_cast< double >(numberPivots);
  printf("PIV%c %d nrow %d startU %d now %d L %d R %d dense %g average %g - shortest %g\n",
    when, numberPivots, numberRows, effectiveStartNumberU_,
    lengthU, lengthL, lengthR, nnd, average, shortestAverage_);
}
#endif
#else
bool ClpFactorization::timeToRefactorize() const
{
  if (coinFactorizationA_) {
    return (coinFactorizationA_->pivots() * 3 > coinFactorizationA_->maximumPivots() * 2 && coinFactorizationA_->numberElementsR() * 3 > (coinFactorizationA_->numberElementsL() + coinFactorizationA_->numberElementsU()) * 2 + 1000 && !coinFactorizationA_->numberDense());
  } else {
    return coinFactorizationB_->pivots() > coinFactorizationB_->numberRows() / 2.45 + 20;
  }
#endif
int ClpFactorization::factorize(ClpSimplex *model,
  int solveType, bool valuesPass)
{
#ifdef CLP_REUSE_ETAS
  model_ = model;
#endif
  //if ((model->specialOptions()&16384))
  //printf("factor at %d iterations\n",model->numberIterations());
  ClpMatrixBase *matrix = model->clpMatrix();
  int numberRows = model->numberRows();
  int numberColumns = model->numberColumns();
  if (!numberRows)
    return 0;
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
  if (!timeInUpdate) {
    printf("ZZZZ,timeInFactor,nRows,nrows_2,\
startU,endU,lengthL,dense,dense_2,nslacks\n");
    printf("YYYY,time,added,dense,dense_2,averageR,averageL,averageU,\
average2R,average2L,average2U,\
scaledDense,scaledDense_2,scaledL,scaledR,scaledU\n");
    printf("WWWW,time,size0,ratio1,ratio05,ratio02\n");
  }
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
  externalTimeStart = CoinCpuTime();
  memset(average, 0, sizeof(average));
  shortest = COIN_DBL_MAX;
  ifPrint = 0;
  if (!model->numberIterations())
    printf("maxfactor %d\n", coinFactorizationA_->maximumPivots());
#endif
  bool anyChanged = false;
  if (coinFactorizationB_) {
    coinFactorizationB_->setStatus(-99);
    int *pivotVariable = model->pivotVariable();
    //returns 0 -okay, -1 singular, -2 too many in basis */
    // allow dense
    int solveMode = 2;
    if (model->numberIterations())
      solveMode += 8;
    if (valuesPass)
      solveMode += 4;
    coinFactorizationB_->setSolveMode(solveMode);
    while (status() < -98) {

      int i;
      int numberBasic = 0;
      int numberRowBasic;
      // Move pivot variables across if they look good
      int *pivotTemp = model->rowArray(0)->getIndices();
      assert(!model->rowArray(0)->getNumElements());
      if (!matrix->rhsOffset(model)) {
        // Seems to prefer things in order so quickest
        // way is to go though like this
        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic)
            pivotTemp[numberBasic++] = i;
        }
        numberRowBasic = numberBasic;
        /* Put column basic variables into pivotVariable
                       This is done by ClpMatrixBase to allow override for gub
                    */
        matrix->generalExpanded(model, 0, numberBasic);
      } else {
        // Long matrix - do a different way
        bool fullSearch = false;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot >= numberColumns) {
            pivotTemp[numberBasic++] = iPivot - numberColumns;
          }
        }
        numberRowBasic = numberBasic;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot < numberColumns) {
            if (iPivot >= 0) {
              pivotTemp[numberBasic++] = iPivot;
            } else {
              // not full basis
              fullSearch = true;
              break;
            }
          }
        }
        if (fullSearch) {
          // do slow way
          numberBasic = 0;
          for (i = 0; i < numberRows; i++) {
            if (model->getRowStatus(i) == ClpSimplex::basic)
              pivotTemp[numberBasic++] = i;
          }
          numberRowBasic = numberBasic;
          /* Put column basic variables into pivotVariable
                            This is done by ClpMatrixBase to allow override for gub
                         */
          matrix->generalExpanded(model, 0, numberBasic);
        }
      }
      if (numberBasic > model->maximumBasic()) {
        // Take out some
        numberBasic = numberRowBasic;
        for (int i = 0; i < numberColumns; i++) {
          if (model->getColumnStatus(i) == ClpSimplex::basic) {
            if (numberBasic < numberRows)
              numberBasic++;
            else
              model->setColumnStatus(i, ClpSimplex::superBasic);
          }
        }
        numberBasic = numberRowBasic;
        matrix->generalExpanded(model, 0, numberBasic);
      } else if (numberBasic < numberRows) {
        // add in some
        int needed = numberRows - numberBasic;
        // move up columns
        for (i = numberBasic - 1; i >= numberRowBasic; i--)
          pivotTemp[i + needed] = pivotTemp[i];
        numberRowBasic = 0;
        numberBasic = numberRows;
        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic) {
            pivotTemp[numberRowBasic++] = i;
          } else if (needed) {
            needed--;
            model->setRowStatus(i, ClpSimplex::basic);
            pivotTemp[numberRowBasic++] = i;
          }
        }
      }
      int numberElements = numberRowBasic;

      // compute how much in basis
      // can change for gub
      int numberColumnBasic = numberBasic - numberRowBasic;

      numberElements += matrix->countBasis(pivotTemp + numberRowBasic,
        numberColumnBasic);
#ifndef NDEBUG
//#define CHECK_CLEAN_BASIS
#ifdef CHECK_CLEAN_BASIS
      int saveNumberElements = numberElements;
#endif
#endif
      // Not needed for dense
      numberElements = 3 * numberBasic + 3 * numberElements + 20000;
      int numberIterations = model->numberIterations();
      coinFactorizationB_->setUsefulInformation(&numberIterations, 0);
      coinFactorizationB_->getAreas(numberRows,
        numberRowBasic + numberColumnBasic, numberElements,
        2 * numberElements);
      // Fill in counts so we can skip part of preProcess
      // This is NOT needed for dense but would be needed for later versions
      CoinFactorizationDouble *elementU;
      int *indexRowU;
      int *startColumnU;
      int *numberInRow;
      int *numberInColumn;
      elementU = coinFactorizationB_->elements();
      indexRowU = coinFactorizationB_->indices();
      startColumnU = coinFactorizationB_->starts();
#ifdef CHECK_CLEAN_BASIS
      for (int i = 0; i < saveNumberElements; i++) {
        elementU[i] = 0.0;
        indexRowU[i] = -1;
      }
      for (int i = 0; i < numberRows; i++)
        startColumnU[i] = -1;
#endif
#ifndef COIN_FAST_CODE
      double slackValue;
      slackValue = coinFactorizationB_->slackValue();
#else
#define slackValue -1.0
#endif
      numberInRow = coinFactorizationB_->numberInRow();
      numberInColumn = coinFactorizationB_->numberInColumn();
      CoinZeroN(numberInRow, numberRows);
      CoinZeroN(numberInColumn, numberRows);
      for (i = 0; i < numberRowBasic; i++) {
        int iRow = pivotTemp[i];
        // Change pivotTemp to correct sequence
        pivotTemp[i] = iRow + numberColumns;
        indexRowU[i] = iRow;
        startColumnU[i] = i;
        elementU[i] = slackValue;
        numberInRow[iRow] = 1;
        numberInColumn[i] = 1;
      }
      startColumnU[numberRowBasic] = numberRowBasic;
      // can change for gub so redo
      numberColumnBasic = numberBasic - numberRowBasic;
      matrix->fillBasis(model,
        pivotTemp + numberRowBasic,
        numberColumnBasic,
        indexRowU,
        startColumnU + numberRowBasic,
        numberInRow,
        numberInColumn + numberRowBasic,
        elementU);
      // recompute number basic
      numberBasic = numberRowBasic + numberColumnBasic;
      for (i = numberBasic; i < numberRows; i++)
        pivotTemp[i] = -1; // mark not there
      if (numberBasic)
        numberElements = startColumnU[numberBasic - 1]
          + numberInColumn[numberBasic - 1];
      else
        numberElements = 0;
#ifdef CHECK_CLEAN_BASIS
      assert(!startColumnU[0]);
      int lastStart = 0;
      for (int i = 0; i < numberRows; i++) {
        assert(startColumnU[i + 1] > lastStart);
        lastStart = startColumnU[i + 1];
      }
      assert(lastStart == saveNumberElements);
      for (int i = 0; i < saveNumberElements; i++) {
        assert(elementU[i]);
        assert(indexRowU[i] >= 0 && indexRowU[i] < numberRows);
      }
#endif
      coinFactorizationB_->preProcess();
      coinFactorizationB_->factor();
      if (coinFactorizationB_->status() == -1 && (coinFactorizationB_->solveMode() % 3) != 0) {
        int solveMode = coinFactorizationB_->solveMode();
        solveMode -= solveMode % 3; // so bottom will be 0
        coinFactorizationB_->setSolveMode(solveMode);
        coinFactorizationB_->setStatus(-99);
      }
      if (coinFactorizationB_->status() == -99)
        continue;
      // If we get here status is 0 or -1
      if (coinFactorizationB_->status() == 0 && numberBasic == numberRows) {
        coinFactorizationB_->postProcess(pivotTemp, pivotVariable);
      } else if (solveType == 0 || solveType == 2 /*||solveType==1*/) {
        // Change pivotTemp to be correct list
        anyChanged = true;
        coinFactorizationB_->makeNonSingular(pivotTemp, numberColumns);
        double *columnLower = model->lowerRegion();
        double *columnUpper = model->upperRegion();
        double *columnActivity = model->solutionRegion();
        double *rowLower = model->lowerRegion(0);
        double *rowUpper = model->upperRegion(0);
        double *rowActivity = model->solutionRegion(0);
        //redo basis - first take ALL out
        int iColumn;
        double largeValue = model->largeValue();
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
            // take out
            if (!valuesPass) {
              double lower = columnLower[iColumn];
              double upper = columnUpper[iColumn];
              double value = columnActivity[iColumn];
              if (lower > -largeValue || upper < largeValue) {
                if (fabs(value - lower) < fabs(value - upper)) {
                  model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
                  columnActivity[iColumn] = lower;
                } else {
                  model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
                  columnActivity[iColumn] = upper;
                }
              } else {
                model->setColumnStatus(iColumn, ClpSimplex::isFree);
              }
            } else {
              model->setColumnStatus(iColumn, ClpSimplex::superBasic);
            }
          }
        }
        int iRow;
        for (iRow = 0; iRow < numberRows; iRow++) {
          if (model->getRowStatus(iRow) == ClpSimplex::basic) {
            // take out
            if (!valuesPass) {
              double lower = columnLower[iRow];
              double upper = columnUpper[iRow];
              double value = columnActivity[iRow];
              if (lower > -largeValue || upper < largeValue) {
                if (fabs(value - lower) < fabs(value - upper)) {
                  model->setRowStatus(iRow, ClpSimplex::atLowerBound);
                  columnActivity[iRow] = lower;
                } else {
                  model->setRowStatus(iRow, ClpSimplex::atUpperBound);
                  columnActivity[iRow] = upper;
                }
              } else {
                model->setRowStatus(iRow, ClpSimplex::isFree);
              }
            } else {
              model->setRowStatus(iRow, ClpSimplex::superBasic);
            }
          }
        }
        for (iRow = 0; iRow < numberRows; iRow++) {
          int iSequence = pivotTemp[iRow];
          assert(iSequence >= 0);
          // basic
          model->setColumnStatus(iSequence, ClpSimplex::basic);
        }
        // signal repeat
        coinFactorizationB_->setStatus(-99);
        // set fixed if they are
        for (iRow = 0; iRow < numberRows; iRow++) {
          if (model->getRowStatus(iRow) != ClpSimplex::basic) {
            if (rowLower[iRow] == rowUpper[iRow]) {
              rowActivity[iRow] = rowLower[iRow];
              model->setRowStatus(iRow, ClpSimplex::isFixed);
            }
          }
        }
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) != ClpSimplex::basic) {
            if (columnLower[iColumn] == columnUpper[iColumn]) {
              columnActivity[iColumn] = columnLower[iColumn];
              model->setColumnStatus(iColumn, ClpSimplex::isFixed);
            }
          }
        }
      }
    }
#ifdef CLP_DEBUG
    // check basic
    CoinIndexedVector region1(2 * numberRows);
    CoinIndexedVector region2B(2 * numberRows);
    int iPivot;
    double *arrayB = region2B.denseVector();
    int i;
    for (iPivot = 0; iPivot < numberRows; iPivot++) {
      int iSequence = pivotVariable[iPivot];
      model->unpack(&region2B, iSequence);
      coinFactorizationB_->updateColumn(&region1, &region2B);
      if (fabs(arrayB[iPivot] - 1.0) < 1.0e-4) {
        // OK?
        arrayB[iPivot] = 0.0;
      } else {
        assert(fabs(arrayB[iPivot]) < 1.0e-4);
        for (i = 0; i < numberRows; i++) {
          if (fabs(arrayB[i] - 1.0) < 1.0e-4)
            break;
        }
        assert(i < numberRows);
        printf("variable on row %d landed up on row %d\n", iPivot, i);
        arrayB[i] = 0.0;
      }
      for (i = 0; i < numberRows; i++)
        assert(fabs(arrayB[i]) < 1.0e-4);
      region2B.clear();
    }
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(2);
#endif
    if (anyChanged && model->algorithm() < 0 && solveType > 0) {
      double dummyCost;
      static_cast< ClpSimplexDual * >(model)->changeBounds(3,
        NULL, dummyCost);
    }
    return coinFactorizationB_->status();
  }
  // If too many compressions increase area
  if (coinFactorizationA_->pivots() > 1 && coinFactorizationA_->numberCompressions() * 10 > coinFactorizationA_->pivots() + 10) {
    coinFactorizationA_->areaFactor(coinFactorizationA_->areaFactor() * 1.1);
  }
  //int numberPivots=coinFactorizationA_->pivots();
#if 0
     if (model->algorithm() > 0)
          numberSave = -1;
#endif
#ifndef SLIM_CLP
  if (!networkBasis_ || doCheck) {
#endif
    coinFactorizationA_->setStatus(-99);
    int *pivotVariable = model->pivotVariable();
    int nTimesRound = 0;
    //returns 0 -okay, -1 singular, -2 too many in basis, -99 memory */
    while (coinFactorizationA_->status() < -98) {
      nTimesRound++;

      int i;
      int numberBasic = 0;
      int numberRowBasic;
      // Move pivot variables across if they look good
      int *pivotTemp = model->rowArray(0)->getIndices();
      assert(!model->rowArray(0)->getNumElements());
      if (!matrix->rhsOffset(model)) {
#if 0
                    if (numberSave > 0) {
                         int nStill = 0;
                         int nAtBound = 0;
                         int nZeroDual = 0;
                         CoinIndexedVector * array = model->rowArray(3);
                         CoinIndexedVector * objArray = model->columnArray(1);
                         array->clear();
                         objArray->clear();
                         double * cost = model->costRegion();
                         double tolerance = model->primalTolerance();
                         double offset = 0.0;
                         for (i = 0; i < numberRows; i++) {
                              int iPivot = pivotVariable[i];
                              if (iPivot < numberColumns && isDense(iPivot)) {
                                   if (model->getColumnStatus(iPivot) == ClpSimplex::basic) {
                                        nStill++;
                                        double value = model->solutionRegion()[iPivot];
                                        double dual = model->dualRowSolution()[i];
                                        double lower = model->lowerRegion()[iPivot];
                                        double upper = model->upperRegion()[iPivot];
                                        ClpSimplex::Status status;
                                        if (fabs(value - lower) < tolerance) {
                                             status = ClpSimplex::atLowerBound;
                                             nAtBound++;
                                        } else if (fabs(value - upper) < tolerance) {
                                             nAtBound++;
                                             status = ClpSimplex::atUpperBound;
                                        } else if (value > lower && value < upper) {
                                             status = ClpSimplex::superBasic;
                                        } else {
                                             status = ClpSimplex::basic;
                                        }
                                        if (status != ClpSimplex::basic) {
                                             if (model->getRowStatus(i) != ClpSimplex::basic) {
                                                  model->setColumnStatus(iPivot, ClpSimplex::atLowerBound);
                                                  model->setRowStatus(i, ClpSimplex::basic);
                                                  pivotVariable[i] = i + numberColumns;
                                                  model->dualRowSolution()[i] = 0.0;
                                                  model->djRegion(0)[i] = 0.0;
                                                  array->add(i, dual);
                                                  offset += dual * model->solutionRegion(0)[i];
                                             }
                                        }
                                        if (fabs(dual) < 1.0e-5)
                                             nZeroDual++;
                                   }
                              }
                         }
                         printf("out of %d dense, %d still in basis, %d at bound, %d with zero dual - offset %g\n",
                                numberSave, nStill, nAtBound, nZeroDual, offset);
                         if (array->getNumElements()) {
                              // modify costs
                              model->clpMatrix()->transposeTimes(model, 1.0, array, model->columnArray(0),
                                                                 objArray);
                              array->clear();
                              int n = objArray->getNumElements();
                              int * indices = objArray->getIndices();
                              double * elements = objArray->denseVector();
                              for (i = 0; i < n; i++) {
                                   int iColumn = indices[i];
                                   cost[iColumn] -= elements[iColumn];
                                   elements[iColumn] = 0.0;
                              }
                              objArray->setNumElements(0);
                         }
                    }
#endif
        // Seems to prefer things in order so quickest
        // way is to go though like this
        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic)
            pivotTemp[numberBasic++] = i;
        }
        numberRowBasic = numberBasic;
        /* Put column basic variables into pivotVariable
                       This is done by ClpMatrixBase to allow override for gub
                    */
        matrix->generalExpanded(model, 0, numberBasic);
      } else {
        // Long matrix - do a different way
        bool fullSearch = false;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot >= numberColumns) {
            pivotTemp[numberBasic++] = iPivot - numberColumns;
          }
        }
        numberRowBasic = numberBasic;
        for (i = 0; i < numberRows; i++) {
          int iPivot = pivotVariable[i];
          if (iPivot < numberColumns) {
            if (iPivot >= 0) {
              pivotTemp[numberBasic++] = iPivot;
            } else {
              // not full basis
              fullSearch = true;
              break;
            }
          }
        }
        if (fullSearch) {
          // do slow way
          numberBasic = 0;
          for (i = 0; i < numberRows; i++) {
            if (model->getRowStatus(i) == ClpSimplex::basic)
              pivotTemp[numberBasic++] = i;
          }
          numberRowBasic = numberBasic;
          /* Put column basic variables into pivotVariable
                            This is done by ClpMatrixBase to allow override for gub
                         */
          matrix->generalExpanded(model, 0, numberBasic);
        }
      }
      if (numberBasic > model->maximumBasic()) {
#if 0 // ndef NDEBUG
                    printf("%d basic - should only be %d\n",
                           numberBasic, numberRows);
#endif
        // Take out some
        numberBasic = numberRowBasic;
        for (int i = 0; i < numberColumns; i++) {
          if (model->getColumnStatus(i) == ClpSimplex::basic) {
            if (numberBasic < numberRows)
              numberBasic++;
            else
              model->setColumnStatus(i, ClpSimplex::superBasic);
          }
        }
        numberBasic = numberRowBasic;
        matrix->generalExpanded(model, 0, numberBasic);
      }
#ifndef SLIM_CLP
      // see if matrix a network
#ifndef NO_RTTI
      ClpNetworkMatrix *networkMatrix = dynamic_cast< ClpNetworkMatrix * >(model->clpMatrix());
#else
      ClpNetworkMatrix *networkMatrix = NULL;
      if (model->clpMatrix()->type() == 11)
        networkMatrix = static_cast< ClpNetworkMatrix * >(model->clpMatrix());
#endif
      // If network - still allow ordinary factorization first time for laziness
      if (networkMatrix)
        coinFactorizationA_->setBiasLU(0); // All to U if network
      //int saveMaximumPivots = maximumPivots();
      delete networkBasis_;
      networkBasis_ = NULL;
      if (networkMatrix && !doCheck)
        maximumPivots(1);
#endif
      //printf("L, U, R %d %d %d\n",numberElementsL(),numberElementsU(),numberElementsR());
      while (coinFactorizationA_->status() == -99) {
        // maybe for speed will be better to leave as many regions as possible
        coinFactorizationA_->gutsOfDestructor();
        coinFactorizationA_->gutsOfInitialize(2);
        int numberElements = numberRowBasic;

        // compute how much in basis

        int i;
        // can change for gub
        int numberColumnBasic = numberBasic - numberRowBasic;

        numberElements += matrix->countBasis(pivotTemp + numberRowBasic,
          numberColumnBasic);
        // and recompute as network side say different
        if (model->numberIterations())
          numberRowBasic = numberBasic - numberColumnBasic;
        numberElements = 3 * numberBasic + 3 * numberElements + 20000;
        coinFactorizationA_->getAreas(numberRows,
          numberRowBasic + numberColumnBasic, numberElements,
          2 * numberElements);
        //fill
        // Fill in counts so we can skip part of preProcess
        int *numberInRow = coinFactorizationA_->numberInRow();
        int *numberInColumn = coinFactorizationA_->numberInColumn();
        CoinZeroN(numberInRow, coinFactorizationA_->numberRows() + 1);
        CoinZeroN(numberInColumn, coinFactorizationA_->maximumColumnsExtra() + 1);
        CoinFactorizationDouble *elementU = coinFactorizationA_->elementU();
        int *indexRowU = coinFactorizationA_->indexRowU();
        int *startColumnU = coinFactorizationA_->startColumnU();
#ifndef COIN_FAST_CODE
        double slackValue = coinFactorizationA_->slackValue();
#endif
        for (i = 0; i < numberRowBasic; i++) {
          int iRow = pivotTemp[i];
          indexRowU[i] = iRow;
          startColumnU[i] = i;
          elementU[i] = slackValue;
          numberInRow[iRow] = 1;
          numberInColumn[i] = 1;
        }
        startColumnU[numberRowBasic] = numberRowBasic;
        // can change for gub so redo
        numberColumnBasic = numberBasic - numberRowBasic;
        matrix->fillBasis(model,
          pivotTemp + numberRowBasic,
          numberColumnBasic,
          indexRowU,
          startColumnU + numberRowBasic,
          numberInRow,
          numberInColumn + numberRowBasic,
          elementU);
#if 0
                    {
                         printf("%d row basic, %d column basic\n", numberRowBasic, numberColumnBasic);
                         for (int i = 0; i < numberElements; i++)
                              printf("row %d col %d value %g\n", indexRowU[i], indexColumnU_[i],
                                     elementU[i]);
                    }
#endif
        // recompute number basic
        numberBasic = numberRowBasic + numberColumnBasic;
        if (numberBasic)
          numberElements = startColumnU[numberBasic - 1]
            + numberInColumn[numberBasic - 1];
        else
          numberElements = 0;
#ifdef CLP_FACTORIZATION_NEW_TIMING
        lastNumberPivots_ = 0;
        effectiveStartNumberU_ = numberElements - numberRows;
        //printf("%d slacks,%d in U at beginning\n",
        //numberRowBasic,numberElements);
#endif
        coinFactorizationA_->setNumberElementsU(numberElements);
        //saveFactorization("dump.d");
        if (coinFactorizationA_->biasLU() >= 3 || coinFactorizationA_->numberRows() != coinFactorizationA_->numberColumns())
          coinFactorizationA_->preProcess(2);
        else
          coinFactorizationA_->preProcess(3); // no row copy
        coinFactorizationA_->factor();
#ifdef CLP_FACTORIZATION_NEW_TIMING
        endLengthU_ = coinFactorizationA_->numberElements() - coinFactorizationA_->numberDense() * coinFactorizationA_->numberDense()
          - coinFactorizationA_->numberElementsL();
#endif
        if (coinFactorizationA_->status() == -99) {
          // get more memory
          coinFactorizationA_->areaFactor(2.0 * coinFactorizationA_->areaFactor());
        } else if (coinFactorizationA_->status() == -1 && (model->numberIterations() == 0 || nTimesRound > 2) && coinFactorizationA_->denseThreshold()) {
          // Round again without dense
          coinFactorizationA_->setDenseThreshold(0);
          coinFactorizationA_->setStatus(-99);
        }
      }
      // If we get here status is 0 or -1
      if (coinFactorizationA_->status() == 0) {
        // We may need to tamper with order and redo - e.g. network with side
        int useNumberRows = numberRows;
        // **** we will also need to add test in dual steepest to do
        // as we do for network
        matrix->generalExpanded(model, 12, useNumberRows);
        const int *permuteBack = coinFactorizationA_->permuteBack();
        const int *back = coinFactorizationA_->pivotColumnBack();
        //int * pivotTemp = pivotColumn_.array();
        //ClpDisjointCopyN ( pivotVariable, numberRows , pivotTemp  );
#ifndef NDEBUG
        CoinFillN(pivotVariable, numberRows, -1);
#endif
        // Redo pivot order
        for (i = 0; i < numberRowBasic; i++) {
          int k = pivotTemp[i];
          // so rowIsBasic[k] would be permuteBack[back[i]]
          int j = permuteBack[back[i]];
          assert(pivotVariable[j] == -1);
          pivotVariable[j] = k + numberColumns;
        }
        for (; i < useNumberRows; i++) {
          int k = pivotTemp[i];
          // so rowIsBasic[k] would be permuteBack[back[i]]
          int j = permuteBack[back[i]];
          assert(pivotVariable[j] == -1);
          pivotVariable[j] = k;
        }
#if 0
                    if (numberSave >= 0) {
                         numberSave = numberDense_;
                         memset(saveList, 0, ((coinFactorizationA_->numberRows() + 31) >> 5)*sizeof(int));
                         for (i = coinFactorizationA_->numberRows() - numberSave; i < coinFactorizationA_->numberRows(); i++) {
                              int k = pivotTemp[pivotColumn_.array()[i]];
                              setDense(k);
                         }
                    }
#endif
        // Set up permutation vector
        // these arrays start off as copies of permute
        // (and we could use permute_ instead of pivotColumn (not back though))
        ClpDisjointCopyN(coinFactorizationA_->permute(), useNumberRows, coinFactorizationA_->pivotColumn());
        ClpDisjointCopyN(coinFactorizationA_->permuteBack(), useNumberRows, coinFactorizationA_->pivotColumnBack());
#ifndef SLIM_CLP
        if (networkMatrix) {
          maximumPivots(CoinMax(2000, maximumPivots()));
          // redo arrays
          for (int iRow = 0; iRow < 4; iRow++) {
            int length = model->numberRows() + maximumPivots();
            if (iRow == 3 || model->objectiveAsObject()->type() > 1)
              length += model->numberColumns();
            model->rowArray(iRow)->reserve(length);
          }
          // create network factorization
          if (doCheck)
            delete networkBasis_; // temp
          networkBasis_ = new ClpNetworkBasis(model, coinFactorizationA_->numberRows(),
            coinFactorizationA_->pivotRegion(),
            coinFactorizationA_->permuteBack(),
            coinFactorizationA_->startColumnU(),
            coinFactorizationA_->numberInColumn(),
            coinFactorizationA_->indexRowU(),
            coinFactorizationA_->elementU());
          // kill off arrays in ordinary factorization
          if (!doCheck) {
            coinFactorizationA_->gutsOfDestructor();
            // but make sure coinFactorizationA_->numberRows() set
            coinFactorizationA_->setNumberRows(model->numberRows());
            coinFactorizationA_->setStatus(0);
#if 0
                              // but put back permute arrays so odd things will work
                              int numberRows = model->numberRows();
                              pivotColumnBack_ = new int [numberRows];
                              permute_ = new int [numberRows];
                              int i;
                              for (i = 0; i < numberRows; i++) {
                                   pivotColumnBack_[i] = i;
                                   permute_[i] = i;
                              }
#endif
          }
        } else {
#endif
          // See if worth going sparse and when
          coinFactorizationA_->checkSparse();
#ifndef SLIM_CLP
        }
#endif
      } else if (coinFactorizationA_->status() == -1 && (solveType == 0 || solveType == 2)) {
        // This needs redoing as it was merged coding - does not need array
#if 1
        int numberTotal = numberRows + numberColumns;
        int *isBasic = new int[numberTotal];
        int *rowIsBasic = isBasic + numberColumns;
        int *columnIsBasic = isBasic;
        for (i = 0; i < numberTotal; i++)
          isBasic[i] = -1;
        for (i = 0; i < numberRowBasic; i++) {
          int iRow = pivotTemp[i];
          rowIsBasic[iRow] = 1;
        }
        for (; i < numberBasic; i++) {
          int iColumn = pivotTemp[i];
          columnIsBasic[iColumn] = 1;
        }
        numberBasic = 0;
        for (i = 0; i < numberRows; i++)
          pivotVariable[i] = -1;
        // mark as basic or non basic
        const int *pivotColumn = coinFactorizationA_->pivotColumn();
        for (i = 0; i < numberRows; i++) {
          if (rowIsBasic[i] >= 0) {
            if (pivotColumn[numberBasic] >= 0) {
              rowIsBasic[i] = pivotColumn[numberBasic];
            } else {
              rowIsBasic[i] = -1;
              model->setRowStatus(i, ClpSimplex::superBasic);
            }
            numberBasic++;
          }
        }
        for (i = 0; i < numberColumns; i++) {
          if (columnIsBasic[i] >= 0) {
            if (pivotColumn[numberBasic] >= 0)
              columnIsBasic[i] = pivotColumn[numberBasic];
            else
              columnIsBasic[i] = -1;
            numberBasic++;
          }
        }
        // leave pivotVariable in useful form for cleaning basis
        int *pivotVariable = model->pivotVariable();
        for (i = 0; i < numberRows; i++) {
          pivotVariable[i] = -1;
        }

        for (i = 0; i < numberRows; i++) {
          if (model->getRowStatus(i) == ClpSimplex::basic) {
            int iPivot = rowIsBasic[i];
            if (iPivot >= 0)
              pivotVariable[iPivot] = i + numberColumns;
          }
        }
        for (i = 0; i < numberColumns; i++) {
          if (model->getColumnStatus(i) == ClpSimplex::basic) {
            int iPivot = columnIsBasic[i];
            if (iPivot >= 0)
              pivotVariable[iPivot] = i;
          }
        }
        delete[] isBasic;
#else
        {
          //int * lastColumn = lastColumn_.array(); // -1 or pivot row
          int *lastRow = coinFactorizationA_->lastRow(); // -1 or pivot sequence (inside sequence)
          for (int i = 0; i < numberRows; i++) {
            int iSeq = lastRow[i];
            if (iSeq >= 0) {
              pivotVariable[i] = pivotTemp[iSeq];
              model->setRowStatus(i, ClpSimplex::superBasic);
            } else {
              pivotVariable[i] = i + numberColumns;
            }
          }
        }
#endif
        double *columnLower = model->lowerRegion();
        double *columnUpper = model->upperRegion();
        double *columnActivity = model->solutionRegion();
        double *rowLower = model->lowerRegion(0);
        double *rowUpper = model->upperRegion(0);
        double *rowActivity = model->solutionRegion(0);
        //redo basis - first take ALL columns out
        int iColumn;
        double largeValue = model->largeValue();
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) == ClpSimplex::basic) {
            // take out
            if (!valuesPass) {
              double lower = columnLower[iColumn];
              double upper = columnUpper[iColumn];
              double value = columnActivity[iColumn];
              if (lower > -largeValue || upper < largeValue) {
                if (fabs(value - lower) < fabs(value - upper)) {
                  model->setColumnStatus(iColumn, ClpSimplex::atLowerBound);
                  columnActivity[iColumn] = lower;
                } else {
                  model->setColumnStatus(iColumn, ClpSimplex::atUpperBound);
                  columnActivity[iColumn] = upper;
                }
              } else {
                model->setColumnStatus(iColumn, ClpSimplex::isFree);
              }
            } else {
              model->setColumnStatus(iColumn, ClpSimplex::superBasic);
            }
          }
        }
        int iRow;
        for (iRow = 0; iRow < numberRows; iRow++) {
          int iSequence = pivotVariable[iRow];
          if (iSequence >= 0) {
            // basic
            if (iSequence >= numberColumns) {
              // slack in - leave
              //assert (iSequence-numberColumns==iRow);
            } else {
              assert(model->getRowStatus(iRow) != ClpSimplex::basic);
              // put back structural
              model->setColumnStatus(iSequence, ClpSimplex::basic);
            }
          } else {
            // put in slack
            model->setRowStatus(iRow, ClpSimplex::basic);
          }
        }
        // Put back any key variables for gub
        int dummy;
        matrix->generalExpanded(model, 1, dummy);
        // signal repeat
        coinFactorizationA_->setStatus(-99);
        // set fixed if they are
        for (iRow = 0; iRow < numberRows; iRow++) {
          if (model->getRowStatus(iRow) != ClpSimplex::basic) {
            if (rowLower[iRow] == rowUpper[iRow]) {
              rowActivity[iRow] = rowLower[iRow];
              model->setRowStatus(iRow, ClpSimplex::isFixed);
            }
          }
        }
        for (iColumn = 0; iColumn < numberColumns; iColumn++) {
          if (model->getColumnStatus(iColumn) != ClpSimplex::basic) {
            if (columnLower[iColumn] == columnUpper[iColumn]) {
              columnActivity[iColumn] = columnLower[iColumn];
              model->setColumnStatus(iColumn, ClpSimplex::isFixed);
            }
          }
        }
      }
    }
#ifndef SLIM_CLP
  } else {
    // network - fake factorization - do nothing
    coinFactorizationA_->setStatus(0);
    coinFactorizationA_->setPivots(0);
  }
#endif
#ifndef SLIM_CLP
  if (!coinFactorizationA_->status()) {
    // take out part if quadratic
    if (model->algorithm() == 2) {
      ClpObjective *obj = model->objectiveAsObject();
#ifndef NDEBUG
      ClpQuadraticObjective *quadraticObj = (dynamic_cast< ClpQuadraticObjective * >(obj));
      assert(quadraticObj);
#else
      ClpQuadraticObjective *quadraticObj = (static_cast< ClpQuadraticObjective * >(obj));
#endif
      CoinPackedMatrix *quadratic = quadraticObj->quadraticObjective();
      int numberXColumns = quadratic->getNumCols();
      assert(numberXColumns < numberColumns);
      int base = numberColumns - numberXColumns;
      int *which = new int[numberXColumns];
      int *pivotVariable = model->pivotVariable();
      int *permute = pivotColumn();
      int i;
      int n = 0;
      for (i = 0; i < numberRows; i++) {
        int iSj = pivotVariable[i] - base;
        if (iSj >= 0 && iSj < numberXColumns)
          which[n++] = permute[i];
      }
      if (n)
        coinFactorizationA_->emptyRows(n, which);
      delete[] which;
    }
  }
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(2);
#endif
  return coinFactorizationA_->status();
}
/* Replaces one Column in basis,
   returns 0=OK, 1=Probably OK, 2=singular, 3=no room
   If checkBeforeModifying is true will do all accuracy checks
   before modifying factorization.  Whether to set this depends on
   speed considerations.  You could just do this on first iteration
   after factorization and thereafter re-factorize
   partial update already in U */
int ClpFactorization::replaceColumn(const ClpSimplex *model,
  CoinIndexedVector *regionSparse,
  CoinIndexedVector *tableauColumn,
  int pivotRow,
  double pivotCheck,
  bool checkBeforeModifying,
  double acceptablePivot)
{
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_NEW_TIMING
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    int nOld = 0;
    int nNew = 0;
    int seq;
#if COIN_BIG_INDEX == 0 && CLP_POOL_MATRIX == 0
    const CoinPackedMatrix *matrix = model->matrix();
    const int *columnLength = matrix->getVectorLengths();
#else
    const int *columnLength = model->clpMatrix()->getVectorLengths();
#endif
    seq = model->sequenceIn();
    if (seq >= 0 && seq < model->numberColumns() + model->numberRows()) {
      if (seq < model->numberColumns()) {
        nNew = columnLength[seq];
      } else {
        nNew = 1;
      }
    }
    seq = model->sequenceOut();
    if (seq >= 0 && seq < model->numberColumns() + model->numberRows()) {
      if (seq < model->numberColumns()) {
        nOld = columnLength[seq];
      } else {
        nOld = 1;
      }
    }
    effectiveStartNumberU_ += nNew - nOld;
#endif
    int returnCode;
    // see if FT
    if (!coinFactorizationA_ || coinFactorizationA_->forrestTomlin()) {
      if (coinFactorizationA_) {
#if ABC_USE_COIN_FACTORIZATION < 2
        returnCode = coinFactorizationA_->replaceColumn(regionSparse,
          pivotRow,
          pivotCheck,
          checkBeforeModifying,
          acceptablePivot);
#else
        // fake btran alpha until I understand
        double btranAlpha = model->alpha();
        double ftAlpha = coinFactorizationA_->checkReplacePart1(regionSparse,
          pivotRow);
        returnCode = coinFactorizationA_->checkReplacePart2(pivotRow,
          btranAlpha,
          model->alpha(),
          ftAlpha,
          acceptablePivot);
        if (returnCode < 2)
          coinFactorizationA_->replaceColumnPart3(regionSparse,
            pivotRow,
            model->alpha());
#endif
      } else {
        bool tab = coinFactorizationB_->wantsTableauColumn();
#ifdef CLP_REUSE_ETAS
        int tempInfo[2];
        tempInfo[1] = model_->sequenceOut();
#else
        int tempInfo[1];
#endif
        tempInfo[0] = model->numberIterations();
        coinFactorizationB_->setUsefulInformation(tempInfo, 1);
        returnCode = coinFactorizationB_->replaceColumn(tab ? tableauColumn : regionSparse,
          pivotRow,
          pivotCheck,
          checkBeforeModifying,
          acceptablePivot);
#ifdef CLP_DEBUG
        // check basic
        int numberRows = coinFactorizationB_->numberRows();
        CoinIndexedVector region1(2 * numberRows);
        CoinIndexedVector region2A(2 * numberRows);
        CoinIndexedVector region2B(2 * numberRows);
        int iPivot;
        double *arrayB = region2B.denseVector();
        int *pivotVariable = model->pivotVariable();
        int i;
        for (iPivot = 0; iPivot < numberRows; iPivot++) {
          int iSequence = pivotVariable[iPivot];
          if (iPivot == pivotRow)
            iSequence = model->sequenceIn();
          model->unpack(&region2B, iSequence);
          coinFactorizationB_->updateColumn(&region1, &region2B);
          assert(fabs(arrayB[iPivot] - 1.0) < 1.0e-4);
          arrayB[iPivot] = 0.0;
          for (i = 0; i < numberRows; i++)
            assert(fabs(arrayB[i]) < 1.0e-4);
          region2B.clear();
        }
#endif
      }
    } else {
      returnCode = coinFactorizationA_->replaceColumnPFI(tableauColumn,
        pivotRow, pivotCheck); // Note array
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(3);
#endif
    return returnCode;

#ifndef SLIM_CLP
  } else {
    if (doCheck) {
      int returnCode = coinFactorizationA_->replaceColumn(regionSparse,
        pivotRow,
        pivotCheck,
        checkBeforeModifying,
        acceptablePivot);
      networkBasis_->replaceColumn(regionSparse,
        pivotRow);
      return returnCode;
    } else {
      // increase number of pivots
      coinFactorizationA_->setPivots(coinFactorizationA_->pivots() + 1);
      return networkBasis_->replaceColumn(regionSparse,
        pivotRow);
    }
  }
#endif
}

/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnFT(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2)
{
#ifdef CLP_DEBUG
  regionSparse->checkClear();
#endif
  if (!numberRows())
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    int returnCode;
    if (coinFactorizationA_) {
      coinFactorizationA_->setCollectStatistics(true);
      returnCode = coinFactorizationA_->updateColumnFT(regionSparse,
        regionSparse2);
      coinFactorizationA_->setCollectStatistics(false);
    } else {
#ifdef CLP_REUSE_ETAS
      int tempInfo[2];
      tempInfo[0] = model_->numberIterations();
      tempInfo[1] = model_->sequenceIn();
      coinFactorizationB_->setUsefulInformation(tempInfo, 2);
#endif
      returnCode = coinFactorizationB_->updateColumnFT(regionSparse,
        regionSparse2);
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(4);
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[coinFactorizationA_->numberRows()];
    int returnCode = coinFactorizationA_->updateColumnFT(regionSparse,
      regionSparse2);
    networkBasis_->updateColumn(regionSparse, save, -1);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, coinFactorizationA_->numberRows() * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      int numberRows = coinFactorizationA_->numberRows();
      for (i = 0; i < numberRows; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
    return 1;
#endif
  }
#endif
}
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumn(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  bool noPermute) const
{
#ifdef CLP_DEBUG
  if (!noPermute)
    regionSparse->checkClear();
#endif
  if (!numberRows())
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    int returnCode;
    if (coinFactorizationA_) {
      coinFactorizationA_->setCollectStatistics(doStatistics_);
      returnCode = coinFactorizationA_->updateColumn(regionSparse,
        regionSparse2,
        noPermute);
      coinFactorizationA_->setCollectStatistics(false);
    } else {
      returnCode = coinFactorizationB_->updateColumn(regionSparse,
        regionSparse2,
        noPermute);
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(5);
#endif
    //#define PRINT_VECTOR
#ifdef PRINT_VECTOR
    printf("Update\n");
    regionSparse2->print();
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[coinFactorizationA_->numberRows()];
    int returnCode = coinFactorizationA_->updateColumn(regionSparse,
      regionSparse2,
      noPermute);
    networkBasis_->updateColumn(regionSparse, save, -1);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, coinFactorizationA_->numberRows() * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      int numberRows = coinFactorizationA_->numberRows();
      for (i = 0; i < numberRows; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    networkBasis_->updateColumn(regionSparse, regionSparse2, -1);
    return 1;
#endif
  }
#endif
}
/* Updates one column (FTRAN) from region2
   Tries to do FT update
   number returned is negative if no room.
   Also updates region3
   region1 starts as zero and is zero at end */
int ClpFactorization::updateTwoColumnsFT(CoinIndexedVector *regionSparse1,
  CoinIndexedVector *regionSparse2,
  CoinIndexedVector *regionSparse3,
  bool noPermuteRegion3)
{
#ifdef CLP_DEBUG
  regionSparse1->checkClear();
#endif
  if (!numberRows())
    return 0;
  int returnCode = 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    if (coinFactorizationA_) {
      coinFactorizationA_->setCollectStatistics(true);
      if (coinFactorizationA_->spaceForForrestTomlin()) {
        assert(regionSparse2->packedMode());
        assert(!regionSparse3->packedMode());
        returnCode = coinFactorizationA_->updateTwoColumnsFT(regionSparse1,
          regionSparse2,
          regionSparse3,
          noPermuteRegion3);
      } else {
        returnCode = coinFactorizationA_->updateColumnFT(regionSparse1,
          regionSparse2);
        coinFactorizationA_->updateColumn(regionSparse1,
          regionSparse3,
          noPermuteRegion3);
      }
      coinFactorizationA_->setCollectStatistics(false);
    } else {
#if 0
               CoinSimpFactorization * fact =
                    dynamic_cast< CoinSimpFactorization*>(coinFactorizationB_);
               if (!fact) {
                    returnCode = coinFactorizationB_->updateColumnFT(regionSparse1,
                                 regionSparse2);
                    coinFactorizationB_->updateColumn(regionSparse1,
                                                      regionSparse3,
                                                      noPermuteRegion3);
               } else {
                    returnCode = fact->updateTwoColumnsFT(regionSparse1,
                                                          regionSparse2,
                                                          regionSparse3,
                                                          noPermuteRegion3);
               }
#else
#ifdef CLP_REUSE_ETAS
      int tempInfo[2];
      tempInfo[0] = model_->numberIterations();
      tempInfo[1] = model_->sequenceIn();
      coinFactorizationB_->setUsefulInformation(tempInfo, 3);
#endif
      returnCode = coinFactorizationB_->updateTwoColumnsFT(
        regionSparse1,
        regionSparse2,
        regionSparse3,
        noPermuteRegion3);
#endif
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(9);
#endif
#ifdef PRINT_VECTOR
    printf("UpdateTwoFT\n");
    regionSparse2->print();
    regionSparse3->print();
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
    returnCode = updateColumnFT(regionSparse1, regionSparse2);
    updateColumn(regionSparse1, regionSparse3, noPermuteRegion3);
  }
#endif
  return returnCode;
}
/* Updates one column (FTRAN) from region2
   number returned is negative if no room
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnForDebug(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  bool noPermute) const
{
  if (!noPermute)
    regionSparse->checkClear();
  if (!coinFactorizationA_->numberRows())
    return 0;
  coinFactorizationA_->setCollectStatistics(false);
  // above doesn't work any more - do by hand
  double save[15];
  memcpy(save, &coinFactorizationA_->ftranCountInput_, sizeof(save));
  int returnCode = coinFactorizationA_->updateColumn(regionSparse,
    regionSparse2,
    noPermute);
  memcpy(&coinFactorizationA_->ftranCountInput_, save, sizeof(save));
  return returnCode;
}
/* Updates one column (BTRAN) from region2
   region1 starts as zero and is zero at end */
int ClpFactorization::updateColumnTranspose(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2) const
{
  if (!numberRows())
    return 0;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    int returnCode;

    if (coinFactorizationA_) {
      coinFactorizationA_->setCollectStatistics(doStatistics_);
      returnCode = coinFactorizationA_->updateColumnTranspose(regionSparse,
        regionSparse2);
      coinFactorizationA_->setCollectStatistics(false);
    } else {
      returnCode = coinFactorizationB_->updateColumnTranspose(regionSparse,
        regionSparse2);
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(6);
#endif
#ifdef PRINT_VECTOR
    printf("UpdateTranspose\n");
    regionSparse2->print();
#endif
    return returnCode;
#ifndef SLIM_CLP
  } else {
#ifdef CHECK_NETWORK
    CoinIndexedVector *save = new CoinIndexedVector(*regionSparse2);
    double *check = new double[coinFactorizationA_->numberRows()];
    int returnCode = coinFactorizationA_->updateColumnTranspose(regionSparse,
      regionSparse2);
    networkBasis_->updateColumnTranspose(regionSparse, save);
    int i;
    double *array = regionSparse2->denseVector();
    int *indices = regionSparse2->getIndices();
    int n = regionSparse2->getNumElements();
    memset(check, 0, coinFactorizationA_->numberRows() * sizeof(double));
    double *array2 = save->denseVector();
    int *indices2 = save->getIndices();
    int n2 = save->getNumElements();
    assert(n == n2);
    if (save->packedMode()) {
      for (i = 0; i < n; i++) {
        check[indices[i]] = array[i];
      }
      for (i = 0; i < n; i++) {
        double value2 = array2[i];
        assert(check[indices2[i]] == value2);
      }
    } else {
      int numberRows = coinFactorizationA_->numberRows();
      for (i = 0; i < numberRows; i++) {
        double value1 = array[i];
        double value2 = array2[i];
        assert(value1 == value2);
      }
    }
    delete save;
    delete[] check;
    return returnCode;
#else
    return networkBasis_->updateColumnTranspose(regionSparse, regionSparse2);
#endif
  }
#endif
}
/* Updates two columns (BTRAN) from regionSparse2 and 3
   regionSparse starts as zero and is zero at end 
   Note - if regionSparse2 packed on input - will be packed on output - same for 3
*/
void ClpFactorization::updateTwoColumnsTranspose(CoinIndexedVector *regionSparse,
  CoinIndexedVector *regionSparse2,
  CoinIndexedVector *regionSparse3) const
{
  if (!numberRows())
    return;
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(-1);
#endif
    if (coinFactorizationA_) {
      coinFactorizationA_->setCollectStatistics(doStatistics_);
#if ABOCA_LITE_FACTORIZATION
      coinFactorizationA_->updateTwoColumnsTranspose(regionSparse,
        regionSparse2, regionSparse3, abcState());
#else
      coinFactorizationA_->updateTwoColumnsTranspose(regionSparse,
        regionSparse2, regionSparse3, 0);
#endif
      coinFactorizationA_->setCollectStatistics(false);
    } else {
      coinFactorizationB_->updateColumnTranspose(regionSparse,
        regionSparse2);
      coinFactorizationB_->updateColumnTranspose(regionSparse,
        regionSparse3);
    }
#ifdef CLP_FACTORIZATION_INSTRUMENT
    factorization_instrument(6);
#endif
#ifndef SLIM_CLP
  } else {
    updateColumnTranspose(regionSparse, regionSparse2);
    updateColumnTranspose(regionSparse, regionSparse3);
  }
#endif
}
/* makes a row copy of L for speed and to allow very sparse problems */
void ClpFactorization::goSparse()
{
#ifndef SLIM_CLP
  if (!networkBasis_) {
#endif
    if (coinFactorizationA_) {
#ifdef CLP_FACTORIZATION_INSTRUMENT
      factorization_instrument(-1);
#endif
      coinFactorizationA_->goSparse();
#ifdef CLP_FACTORIZATION_INSTRUMENT
      factorization_instrument(7);
#endif
    }
  }
}
// Cleans up i.e. gets rid of network basis
void ClpFactorization::cleanUp()
{
#ifndef SLIM_CLP
  delete networkBasis_;
  networkBasis_ = NULL;
#endif
  if (coinFactorizationA_)
    coinFactorizationA_->resetStatistics();
}
/// Says whether to redo pivot order
bool ClpFactorization::needToReorder() const
{
#ifdef CHECK_NETWORK
  return true;
#endif
#ifndef SLIM_CLP
  if (!networkBasis_)
#endif
    return true;
#ifndef SLIM_CLP
  else
    return false;
#endif
}
// Get weighted row list
void ClpFactorization::getWeights(int *weights) const
{
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(-1);
#endif
#ifndef SLIM_CLP
  if (networkBasis_) {
    // Network - just unit
    int numberRows = coinFactorizationA_->numberRows();
    for (int i = 0; i < numberRows; i++)
      weights[i] = 1;
    return;
  }
#endif
  int *numberInRow = coinFactorizationA_->numberInRow();
  int *numberInColumn = coinFactorizationA_->numberInColumn();
  int *permuteBack = coinFactorizationA_->pivotColumnBack();
  int *indexRowU = coinFactorizationA_->indexRowU();
  const int *startColumnU = coinFactorizationA_->startColumnU();
  const int *startRowL = coinFactorizationA_->startRowL();
  int numberRows = coinFactorizationA_->numberRows();
  if (!startRowL || !coinFactorizationA_->numberInRow()) {
    int *temp = new int[numberRows];
    memset(temp, 0, numberRows * sizeof(int));
    int i;
    for (i = 0; i < numberRows; i++) {
      // one for pivot
      temp[i]++;
      int j;
      for (j = startColumnU[i]; j < startColumnU[i] + numberInColumn[i]; j++) {
        int iRow = indexRowU[j];
        temp[iRow]++;
      }
    }
    int *startColumnL = coinFactorizationA_->startColumnL();
    int *indexRowL = coinFactorizationA_->indexRowL();
    int numberL = coinFactorizationA_->numberL();
    int baseL = coinFactorizationA_->baseL();
    for (i = baseL; i < baseL + numberL; i++) {
      int j;
      for (j = startColumnL[i]; j < startColumnL[i + 1]; j++) {
        int iRow = indexRowL[j];
        temp[iRow]++;
      }
    }
    for (i = 0; i < numberRows; i++) {
      int number = temp[i];
      int iPermute = permuteBack[i];
      weights[iPermute] = number;
    }
    delete[] temp;
  } else {
    int i;
    for (i = 0; i < numberRows; i++) {
      int number = startRowL[i + 1] - startRowL[i] + numberInRow[i] + 1;
      //number = startRowL[i+1]-startRowL[i]+1;
      //number = numberInRow[i]+1;
      int iPermute = permuteBack[i];
      weights[iPermute] = number;
    }
  }
#ifdef CLP_FACTORIZATION_INSTRUMENT
  factorization_instrument(8);
#endif
}
#if ABOCA_LITE_FACTORIZATION
// Does btranU part of replaceColumn (skipping entries)
void ClpFactorization::replaceColumn1(CoinIndexedVector *regionSparse,
  int pivotRow)
{
  if (coinFactorizationA_)
    coinFactorizationA_->replaceColumn1(regionSparse, pivotRow);
}
// Does replaceColumn - having already done btranU
int ClpFactorization::replaceColumn2(CoinIndexedVector *regionSparse,
  int pivotRow,
  double pivotCheck)
{
  if (coinFactorizationA_)
    return coinFactorizationA_->replaceColumn2(regionSparse, pivotRow, pivotCheck);
  else
    return 12345678;
}
#endif
// Set tolerances to safer of existing and given
void ClpFactorization::saferTolerances(double zeroValue,
  double pivotValue)
{
  double newValue;
  // better to have small tolerance even if slower
  if (zeroValue > 0.0)
    newValue = zeroValue;
  else
    newValue = -zeroTolerance() * zeroValue;
  zeroTolerance(CoinMin(zeroTolerance(), zeroValue));
  // better to have large tolerance even if slower
  if (pivotValue > 0.0)
    newValue = pivotValue;
  else
    newValue = -pivotTolerance() * pivotValue;
  pivotTolerance(CoinMin(CoinMax(pivotTolerance(), newValue), 0.999));
}
// Sets factorization
void ClpFactorization::setFactorization(ClpFactorization &rhs)
{
  ClpFactorization::operator=(rhs);
}
#endif

/* vi: softtabstop=2 shiftwidth=2 expandtab tabstop=2
*/
